File indexing completed on 2024-06-23 04:35:52
0001 // ASFormatter.cpp 0002 // Copyright (c) 2018 by Jim Pattee <jimp03@email.com>. 0003 // This code is licensed under the MIT License. 0004 // License.md describes the conditions under which this software may be distributed. 0005 0006 //----------------------------------------------------------------------------- 0007 // headers 0008 //----------------------------------------------------------------------------- 0009 0010 #include "astyle.h" 0011 0012 #include <algorithm> 0013 #include <fstream> 0014 0015 //----------------------------------------------------------------------------- 0016 // astyle namespace 0017 //----------------------------------------------------------------------------- 0018 0019 namespace astyle { 0020 // 0021 //----------------------------------------------------------------------------- 0022 // ASFormatter class 0023 //----------------------------------------------------------------------------- 0024 0025 /** 0026 * Constructor of ASFormatter 0027 */ 0028 ASFormatter::ASFormatter() 0029 { 0030 sourceIterator = nullptr; 0031 enhancer = new ASEnhancer; 0032 preBraceHeaderStack = nullptr; 0033 braceTypeStack = nullptr; 0034 parenStack = nullptr; 0035 structStack = nullptr; 0036 questionMarkStack = nullptr; 0037 lineCommentNoIndent = false; 0038 formattingStyle = STYLE_NONE; 0039 braceFormatMode = NONE_MODE; 0040 pointerAlignment = PTR_ALIGN_NONE; 0041 referenceAlignment = REF_SAME_AS_PTR; 0042 objCColonPadMode = COLON_PAD_NO_CHANGE; 0043 lineEnd = LINEEND_DEFAULT; 0044 maxCodeLength = string::npos; 0045 shouldPadCommas = false; 0046 shouldPadOperators = false; 0047 shouldPadParensOutside = false; 0048 shouldPadFirstParen = false; 0049 shouldPadParensInside = false; 0050 shouldPadHeader = false; 0051 shouldStripCommentPrefix = false; 0052 shouldUnPadParens = false; 0053 attachClosingBraceMode = false; 0054 shouldBreakOneLineBlocks = true; 0055 shouldBreakOneLineHeaders = false; 0056 shouldBreakOneLineStatements = true; 0057 shouldConvertTabs = false; 0058 shouldIndentCol1Comments = false; 0059 shouldIndentPreprocBlock = false; 0060 shouldCloseTemplates = false; 0061 shouldAttachExternC = false; 0062 shouldAttachNamespace = false; 0063 shouldAttachClass = false; 0064 shouldAttachClosingWhile = false; 0065 shouldAttachInline = false; 0066 shouldBreakBlocks = false; 0067 shouldBreakClosingHeaderBlocks = false; 0068 shouldBreakClosingHeaderBraces = false; 0069 shouldDeleteEmptyLines = false; 0070 shouldBreakReturnType = false; 0071 shouldBreakReturnTypeDecl = false; 0072 shouldAttachReturnType = false; 0073 shouldAttachReturnTypeDecl = false; 0074 shouldBreakElseIfs = false; 0075 shouldBreakLineAfterLogical = false; 0076 shouldAddBraces = false; 0077 shouldAddOneLineBraces = false; 0078 shouldRemoveBraces = false; 0079 shouldPadMethodColon = false; 0080 shouldPadMethodPrefix = false; 0081 shouldUnPadMethodPrefix = false; 0082 shouldPadReturnType = false; 0083 shouldUnPadReturnType = false; 0084 shouldPadParamType = false; 0085 shouldUnPadParamType = false; 0086 0087 // initialize ASFormatter member vectors 0088 formatterFileType = 9; // reset to an invalid type 0089 headers = new vector<const string*>; 0090 nonParenHeaders = new vector<const string*>; 0091 preDefinitionHeaders = new vector<const string*>; 0092 preCommandHeaders = new vector<const string*>; 0093 operators = new vector<const string*>; 0094 assignmentOperators = new vector<const string*>; 0095 castOperators = new vector<const string*>; 0096 0097 // initialize ASEnhancer member vectors 0098 indentableMacros = new vector<const pair<const string, const string>* >; 0099 } 0100 0101 /** 0102 * Destructor of ASFormatter 0103 */ 0104 ASFormatter::~ASFormatter() 0105 { 0106 // delete ASFormatter stack vectors 0107 deleteContainer(preBraceHeaderStack); 0108 deleteContainer(braceTypeStack); 0109 deleteContainer(parenStack); 0110 deleteContainer(structStack); 0111 deleteContainer(questionMarkStack); 0112 0113 // delete ASFormatter member vectors 0114 formatterFileType = 9; // reset to an invalid type 0115 delete headers; 0116 delete nonParenHeaders; 0117 delete preDefinitionHeaders; 0118 delete preCommandHeaders; 0119 delete operators; 0120 delete assignmentOperators; 0121 delete castOperators; 0122 0123 // delete ASEnhancer member vectors 0124 delete indentableMacros; 0125 0126 // must be done when the ASFormatter object is deleted (not ASBeautifier) 0127 // delete ASBeautifier member vectors 0128 ASBeautifier::deleteBeautifierVectors(); 0129 0130 delete enhancer; 0131 } 0132 0133 /** 0134 * initialize the ASFormatter. 0135 * 0136 * init() should be called every time a ASFormatter object is to start 0137 * formatting a NEW source file. 0138 * init() receives a pointer to a ASSourceIterator object that will be 0139 * used to iterate through the source code. 0140 * 0141 * @param si a pointer to the ASSourceIterator or ASStreamIterator object. 0142 */ 0143 void ASFormatter::init(ASSourceIterator* si) 0144 { 0145 buildLanguageVectors(); 0146 fixOptionVariableConflicts(); 0147 ASBeautifier::init(si); 0148 sourceIterator = si; 0149 0150 enhancer->init(getFileType(), 0151 getIndentLength(), 0152 getTabLength(), 0153 getIndentString() == "\t", 0154 getForceTabIndentation(), 0155 getNamespaceIndent(), 0156 getCaseIndent(), 0157 shouldIndentPreprocBlock, 0158 getPreprocDefineIndent(), 0159 getEmptyLineFill(), 0160 indentableMacros); 0161 0162 initContainer(preBraceHeaderStack, new vector<const string*>); 0163 initContainer(parenStack, new vector<int>); 0164 initContainer(structStack, new vector<bool>); 0165 initContainer(questionMarkStack, new vector<bool>); 0166 parenStack->emplace_back(0); // parenStack must contain this default entry 0167 initContainer(braceTypeStack, new vector<BraceType>); 0168 braceTypeStack->emplace_back(NULL_TYPE); // braceTypeStack must contain this default entry 0169 clearFormattedLineSplitPoints(); 0170 0171 currentHeader = nullptr; 0172 currentLine = ""; 0173 readyFormattedLine = ""; 0174 formattedLine = ""; 0175 verbatimDelimiter = ""; 0176 currentChar = ' '; 0177 previousChar = ' '; 0178 previousCommandChar = ' '; 0179 previousNonWSChar = ','; // not a potential name or operator 0180 quoteChar = '"'; 0181 preprocBlockEnd = 0; 0182 charNum = 0; 0183 checksumIn = 0; 0184 checksumOut = 0; 0185 currentLineFirstBraceNum = string::npos; 0186 formattedLineCommentNum = 0; 0187 leadingSpaces = 0; 0188 previousReadyFormattedLineLength = string::npos; 0189 preprocBraceTypeStackSize = 0; 0190 spacePadNum = 0; 0191 methodAttachCharNum = string::npos; 0192 methodAttachLineNum = 0; 0193 methodBreakCharNum = string::npos; 0194 methodBreakLineNum = 0; 0195 nextLineSpacePadNum = 0; 0196 objCColonAlign = 0; 0197 templateDepth = 0; 0198 squareBracketCount = 0; 0199 runInIndentChars = 0; 0200 tabIncrementIn = 0; 0201 previousBraceType = NULL_TYPE; 0202 0203 isVirgin = true; 0204 isInVirginLine = true; 0205 isInLineComment = false; 0206 isInComment = false; 0207 isInCommentStartLine = false; 0208 noTrimCommentContinuation = false; 0209 isInPreprocessor = false; 0210 isInPreprocessorBeautify = false; 0211 doesLineStartComment = false; 0212 lineEndsInCommentOnly = false; 0213 lineIsCommentOnly = false; 0214 lineIsLineCommentOnly = false; 0215 lineIsEmpty = false; 0216 isImmediatelyPostCommentOnly = false; 0217 isImmediatelyPostEmptyLine = false; 0218 isInClassInitializer = false; 0219 isInQuote = false; 0220 isInVerbatimQuote = false; 0221 haveLineContinuationChar = false; 0222 isInQuoteContinuation = false; 0223 isHeaderInMultiStatementLine = false; 0224 isSpecialChar = false; 0225 isNonParenHeader = false; 0226 foundNamespaceHeader = false; 0227 foundClassHeader = false; 0228 foundStructHeader = false; 0229 foundInterfaceHeader = false; 0230 foundPreDefinitionHeader = false; 0231 foundPreCommandHeader = false; 0232 foundPreCommandMacro = false; 0233 foundTrailingReturnType = false; 0234 foundCastOperator = false; 0235 foundQuestionMark = false; 0236 isInLineBreak = false; 0237 endOfAsmReached = false; 0238 endOfCodeReached = false; 0239 isFormattingModeOff = false; 0240 isInEnum = false; 0241 isInExecSQL = false; 0242 isInAsm = false; 0243 isInAsmOneLine = false; 0244 isInAsmBlock = false; 0245 isLineReady = false; 0246 elseHeaderFollowsComments = false; 0247 caseHeaderFollowsComments = false; 0248 isPreviousBraceBlockRelated = false; 0249 isInPotentialCalculation = false; 0250 needHeaderOpeningBrace = false; 0251 shouldBreakLineAtNextChar = false; 0252 shouldKeepLineUnbroken = false; 0253 shouldReparseCurrentChar = false; 0254 passedSemicolon = false; 0255 passedColon = false; 0256 isImmediatelyPostNonInStmt = false; 0257 isCharImmediatelyPostNonInStmt = false; 0258 isInTemplate = false; 0259 isImmediatelyPostComment = false; 0260 isImmediatelyPostLineComment = false; 0261 isImmediatelyPostEmptyBlock = false; 0262 isImmediatelyPostObjCMethodPrefix = false; 0263 isImmediatelyPostPreprocessor = false; 0264 isImmediatelyPostReturn = false; 0265 isImmediatelyPostThrow = false; 0266 isImmediatelyPostNewDelete = false; 0267 isImmediatelyPostOperator = false; 0268 isImmediatelyPostTemplate = false; 0269 isImmediatelyPostPointerOrReference = false; 0270 isCharImmediatelyPostReturn = false; 0271 isCharImmediatelyPostThrow = false; 0272 isCharImmediatelyPostNewDelete = false; 0273 isCharImmediatelyPostOperator = false; 0274 isCharImmediatelyPostComment = false; 0275 isPreviousCharPostComment = false; 0276 isCharImmediatelyPostLineComment = false; 0277 isCharImmediatelyPostOpenBlock = false; 0278 isCharImmediatelyPostCloseBlock = false; 0279 isCharImmediatelyPostTemplate = false; 0280 isCharImmediatelyPostPointerOrReference = false; 0281 isInObjCInterface = false; 0282 isInObjCMethodDefinition = false; 0283 isInObjCReturnType = false; 0284 isInObjCParam = false; 0285 isInObjCSelector = false; 0286 breakCurrentOneLineBlock = false; 0287 shouldRemoveNextClosingBrace = false; 0288 isInBraceRunIn = false; 0289 returnTypeChecked = false; 0290 currentLineBeginsWithBrace = false; 0291 isPrependPostBlockEmptyLineRequested = false; 0292 isAppendPostBlockEmptyLineRequested = false; 0293 isIndentableProprocessor = false; 0294 isIndentableProprocessorBlock = false; 0295 prependEmptyLine = false; 0296 appendOpeningBrace = false; 0297 foundClosingHeader = false; 0298 isImmediatelyPostHeader = false; 0299 isInHeader = false; 0300 isInCase = false; 0301 isFirstPreprocConditional = false; 0302 processedFirstConditional = false; 0303 isJavaStaticConstructor = false; 0304 } 0305 0306 /** 0307 * build vectors for each programing language 0308 * depending on the file extension. 0309 */ 0310 void ASFormatter::buildLanguageVectors() 0311 { 0312 if (getFileType() == formatterFileType) // don't build unless necessary 0313 return; 0314 0315 formatterFileType = getFileType(); 0316 0317 headers->clear(); 0318 nonParenHeaders->clear(); 0319 preDefinitionHeaders->clear(); 0320 preCommandHeaders->clear(); 0321 operators->clear(); 0322 assignmentOperators->clear(); 0323 castOperators->clear(); 0324 indentableMacros->clear(); // ASEnhancer 0325 0326 ASResource::buildHeaders(headers, getFileType()); 0327 ASResource::buildNonParenHeaders(nonParenHeaders, getFileType()); 0328 ASResource::buildPreDefinitionHeaders(preDefinitionHeaders, getFileType()); 0329 ASResource::buildPreCommandHeaders(preCommandHeaders, getFileType()); 0330 ASResource::buildOperators(operators, getFileType()); 0331 ASResource::buildAssignmentOperators(assignmentOperators); 0332 ASResource::buildCastOperators(castOperators); 0333 ASResource::buildIndentableMacros(indentableMacros); //ASEnhancer 0334 } 0335 0336 /** 0337 * set the variables for each predefined style. 0338 * this will override any previous settings. 0339 */ 0340 void ASFormatter::fixOptionVariableConflicts() 0341 { 0342 if (formattingStyle == STYLE_ALLMAN) 0343 { 0344 setBraceFormatMode(BREAK_MODE); 0345 } 0346 else if (formattingStyle == STYLE_JAVA) 0347 { 0348 setBraceFormatMode(ATTACH_MODE); 0349 } 0350 else if (formattingStyle == STYLE_KR) 0351 { 0352 setBraceFormatMode(LINUX_MODE); 0353 } 0354 else if (formattingStyle == STYLE_STROUSTRUP) 0355 { 0356 setBraceFormatMode(LINUX_MODE); 0357 setBreakClosingHeaderBracesMode(true); 0358 } 0359 else if (formattingStyle == STYLE_WHITESMITH) 0360 { 0361 setBraceFormatMode(BREAK_MODE); 0362 setBraceIndent(true); 0363 setClassIndent(true); // avoid hanging indent with access modifiers 0364 setSwitchIndent(true); // avoid hanging indent with case statements 0365 } 0366 else if (formattingStyle == STYLE_VTK) 0367 { 0368 // the unindented class brace does NOT cause a hanging indent like Whitesmith 0369 setBraceFormatMode(BREAK_MODE); 0370 setBraceIndentVtk(true); // sets both braceIndent and braceIndentVtk 0371 setSwitchIndent(true); // avoid hanging indent with case statements 0372 } 0373 else if (formattingStyle == STYLE_RATLIFF) 0374 { 0375 // attached braces can have hanging indents with the closing brace 0376 setBraceFormatMode(ATTACH_MODE); 0377 setBraceIndent(true); 0378 setClassIndent(true); // avoid hanging indent with access modifiers 0379 setSwitchIndent(true); // avoid hanging indent with case statements 0380 } 0381 else if (formattingStyle == STYLE_GNU) 0382 { 0383 setBraceFormatMode(BREAK_MODE); 0384 setBlockIndent(true); 0385 } 0386 else if (formattingStyle == STYLE_LINUX) 0387 { 0388 setBraceFormatMode(LINUX_MODE); 0389 // always for Linux style 0390 setMinConditionalIndentOption(MINCOND_ONEHALF); 0391 } 0392 else if (formattingStyle == STYLE_HORSTMANN) 0393 { 0394 setBraceFormatMode(RUN_IN_MODE); 0395 setSwitchIndent(true); 0396 } 0397 else if (formattingStyle == STYLE_1TBS) 0398 { 0399 setBraceFormatMode(LINUX_MODE); 0400 setAddBracesMode(true); 0401 setRemoveBracesMode(false); 0402 } 0403 else if (formattingStyle == STYLE_GOOGLE) 0404 { 0405 setBraceFormatMode(ATTACH_MODE); 0406 setModifierIndent(true); 0407 setClassIndent(false); 0408 } 0409 else if (formattingStyle == STYLE_MOZILLA) 0410 { 0411 setBraceFormatMode(LINUX_MODE); 0412 } 0413 else if (formattingStyle == STYLE_PICO) 0414 { 0415 setBraceFormatMode(RUN_IN_MODE); 0416 setAttachClosingBraceMode(true); 0417 setSwitchIndent(true); 0418 setBreakOneLineBlocksMode(false); 0419 setBreakOneLineStatementsMode(false); 0420 // add-braces won't work for pico, but it could be fixed if necessary 0421 // both options should be set to true 0422 if (shouldAddBraces) 0423 shouldAddOneLineBraces = true; 0424 } 0425 else if (formattingStyle == STYLE_LISP) 0426 { 0427 setBraceFormatMode(ATTACH_MODE); 0428 setAttachClosingBraceMode(true); 0429 setBreakOneLineStatementsMode(false); 0430 // add-one-line-braces won't work for lisp 0431 // only shouldAddBraces should be set to true 0432 if (shouldAddOneLineBraces) 0433 { 0434 shouldAddBraces = true; 0435 shouldAddOneLineBraces = false; 0436 } 0437 } 0438 setMinConditionalIndentLength(); 0439 // if not set by indent=force-tab-x set equal to indentLength 0440 if (getTabLength() == 0) 0441 setDefaultTabLength(); 0442 // add-one-line-braces implies keep-one-line-blocks 0443 if (shouldAddOneLineBraces) 0444 setBreakOneLineBlocksMode(false); 0445 // don't allow add-braces and remove-braces 0446 if (shouldAddBraces || shouldAddOneLineBraces) 0447 setRemoveBracesMode(false); 0448 // don't allow break-return-type and attach-return-type 0449 if (shouldBreakReturnType) 0450 shouldAttachReturnType = false; 0451 if (shouldBreakReturnTypeDecl) 0452 shouldAttachReturnTypeDecl = false; 0453 // don't allow indent-classes and indent-modifiers 0454 if (getClassIndent()) 0455 setModifierIndent(false); 0456 } 0457 0458 /** 0459 * get the next formatted line. 0460 * 0461 * @return formatted line. 0462 */ 0463 string ASFormatter::nextLine() 0464 { 0465 const string* newHeader = nullptr; 0466 isInVirginLine = isVirgin; 0467 isCharImmediatelyPostComment = false; 0468 isPreviousCharPostComment = false; 0469 isCharImmediatelyPostLineComment = false; 0470 isCharImmediatelyPostOpenBlock = false; 0471 isCharImmediatelyPostCloseBlock = false; 0472 isCharImmediatelyPostTemplate = false; 0473 0474 while (!isLineReady) 0475 { 0476 if (shouldReparseCurrentChar) 0477 shouldReparseCurrentChar = false; 0478 else if (!getNextChar()) 0479 { 0480 breakLine(); 0481 continue; 0482 } 0483 else // stuff to do when reading a new character... 0484 { 0485 // make sure that a virgin '{' at the beginning of the file will be treated as a block... 0486 if (isInVirginLine && currentChar == '{' 0487 && currentLineBeginsWithBrace 0488 && previousCommandChar == ' ') 0489 previousCommandChar = '{'; 0490 if (isInClassInitializer 0491 && isBraceType(braceTypeStack->back(), COMMAND_TYPE)) 0492 isInClassInitializer = false; 0493 if (isInBraceRunIn) 0494 isInLineBreak = false; 0495 if (!isWhiteSpace(currentChar)) 0496 isInBraceRunIn = false; 0497 isPreviousCharPostComment = isCharImmediatelyPostComment; 0498 isCharImmediatelyPostComment = false; 0499 isCharImmediatelyPostTemplate = false; 0500 isCharImmediatelyPostReturn = false; 0501 isCharImmediatelyPostThrow = false; 0502 isCharImmediatelyPostNewDelete = false; 0503 isCharImmediatelyPostOperator = false; 0504 isCharImmediatelyPostPointerOrReference = false; 0505 isCharImmediatelyPostOpenBlock = false; 0506 isCharImmediatelyPostCloseBlock = false; 0507 } 0508 0509 if ((lineIsLineCommentOnly || lineIsCommentOnly) 0510 && currentLine.find("*INDENT-ON*", charNum) != string::npos 0511 && isFormattingModeOff) 0512 { 0513 isFormattingModeOff = false; 0514 breakLine(); 0515 formattedLine = currentLine; 0516 charNum = (int) currentLine.length() - 1; 0517 continue; 0518 } 0519 if (isFormattingModeOff) 0520 { 0521 breakLine(); 0522 formattedLine = currentLine; 0523 charNum = (int) currentLine.length() - 1; 0524 continue; 0525 } 0526 if ((lineIsLineCommentOnly || lineIsCommentOnly) 0527 && currentLine.find("*INDENT-OFF*", charNum) != string::npos) 0528 { 0529 isFormattingModeOff = true; 0530 if (isInLineBreak) // is true if not the first line 0531 breakLine(); 0532 formattedLine = currentLine; 0533 charNum = (int) currentLine.length() - 1; 0534 continue; 0535 } 0536 0537 if (shouldBreakLineAtNextChar) 0538 { 0539 if (isWhiteSpace(currentChar) && !lineIsEmpty) 0540 continue; 0541 isInLineBreak = true; 0542 shouldBreakLineAtNextChar = false; 0543 } 0544 0545 if (isInExecSQL && !passedSemicolon) 0546 { 0547 if (currentChar == ';') 0548 passedSemicolon = true; 0549 appendCurrentChar(); 0550 continue; 0551 } 0552 0553 if (isInLineComment) 0554 { 0555 formatLineCommentBody(); 0556 continue; 0557 } 0558 else if (isInComment) 0559 { 0560 formatCommentBody(); 0561 continue; 0562 } 0563 0564 else if (isInQuote) 0565 { 0566 formatQuoteBody(); 0567 continue; 0568 } 0569 0570 // not in quote or comment or line comment 0571 0572 if (isSequenceReached("//")) 0573 { 0574 formatLineCommentOpener(); 0575 testForTimeToSplitFormattedLine(); 0576 continue; 0577 } 0578 else if (isSequenceReached("/*")) 0579 { 0580 formatCommentOpener(); 0581 testForTimeToSplitFormattedLine(); 0582 continue; 0583 } 0584 else if (currentChar == '"' 0585 || (currentChar == '\'' && !isDigitSeparator(currentLine, charNum))) 0586 { 0587 formatQuoteOpener(); 0588 testForTimeToSplitFormattedLine(); 0589 continue; 0590 } 0591 // treat these preprocessor statements as a line comment 0592 else if (currentChar == '#' 0593 && currentLine.find_first_not_of(" \t") == (size_t) charNum) 0594 { 0595 string preproc = trim(currentLine.c_str() + charNum + 1); 0596 if (preproc.length() > 0 0597 && isCharPotentialHeader(preproc, 0) 0598 && (findKeyword(preproc, 0, "region") 0599 || findKeyword(preproc, 0, "endregion") 0600 || findKeyword(preproc, 0, "error") 0601 || findKeyword(preproc, 0, "warning") 0602 || findKeyword(preproc, 0, "line"))) 0603 { 0604 currentLine = rtrim(currentLine); // trim the end only 0605 // check for run-in 0606 if (formattedLine.length() > 0 && formattedLine[0] == '{') 0607 { 0608 isInLineBreak = true; 0609 isInBraceRunIn = false; 0610 } 0611 if (previousCommandChar == '}') 0612 currentHeader = nullptr; 0613 isInLineComment = true; 0614 appendCurrentChar(); 0615 continue; 0616 } 0617 } 0618 0619 if (isInPreprocessor) 0620 { 0621 appendCurrentChar(); 0622 continue; 0623 } 0624 0625 if (isInTemplate && shouldCloseTemplates) 0626 { 0627 if (previousNonWSChar == '>' && isWhiteSpace(currentChar) && peekNextChar() == '>') 0628 continue; 0629 } 0630 0631 if (shouldRemoveNextClosingBrace && currentChar == '}') 0632 { 0633 currentLine[charNum] = currentChar = ' '; 0634 shouldRemoveNextClosingBrace = false; 0635 assert(adjustChecksumIn(-'}')); 0636 if (isEmptyLine(currentLine)) 0637 continue; 0638 } 0639 0640 // handle white space - needed to simplify the rest. 0641 if (isWhiteSpace(currentChar)) 0642 { 0643 appendCurrentChar(); 0644 continue; 0645 } 0646 0647 /* not in MIDDLE of quote or comment or SQL or white-space of any type ... */ 0648 0649 // check if in preprocessor 0650 // ** isInPreprocessor will be automatically reset at the beginning 0651 // of a new line in getnextChar() 0652 if (currentChar == '#' 0653 && currentLine.find_first_not_of(" \t") == (size_t) charNum 0654 && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)) 0655 { 0656 isInPreprocessor = true; 0657 // check for run-in 0658 if (formattedLine.length() > 0 && formattedLine[0] == '{') 0659 { 0660 isInLineBreak = true; 0661 isInBraceRunIn = false; 0662 } 0663 processPreprocessor(); 0664 // if top level it is potentially indentable 0665 if (shouldIndentPreprocBlock 0666 && (isBraceType(braceTypeStack->back(), NULL_TYPE) 0667 || isBraceType(braceTypeStack->back(), NAMESPACE_TYPE)) 0668 && !foundClassHeader 0669 && !isInClassInitializer 0670 && sourceIterator->tellg() > preprocBlockEnd) 0671 { 0672 // indent the #if preprocessor blocks 0673 string preproc = ASBeautifier::extractPreprocessorStatement(currentLine); 0674 if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef 0675 { 0676 if (isImmediatelyPostPreprocessor) 0677 breakLine(); 0678 isIndentableProprocessorBlock = isIndentablePreprocessorBlock(currentLine, charNum); 0679 isIndentableProprocessor = isIndentableProprocessorBlock; 0680 } 0681 } 0682 if (isIndentableProprocessorBlock 0683 && charNum < (int) currentLine.length() - 1 0684 && isWhiteSpace(currentLine[charNum + 1])) 0685 { 0686 size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1); 0687 if (nextText != string::npos) 0688 currentLine.erase(charNum + 1, nextText - charNum - 1); 0689 } 0690 if (isIndentableProprocessorBlock 0691 && sourceIterator->tellg() >= preprocBlockEnd) 0692 isIndentableProprocessorBlock = false; 0693 // need to fall thru here to reset the variables 0694 } 0695 0696 /* not in preprocessor ... */ 0697 0698 if (isImmediatelyPostComment) 0699 { 0700 caseHeaderFollowsComments = false; 0701 isImmediatelyPostComment = false; 0702 isCharImmediatelyPostComment = true; 0703 } 0704 0705 if (isImmediatelyPostLineComment) 0706 { 0707 caseHeaderFollowsComments = false; 0708 isImmediatelyPostLineComment = false; 0709 isCharImmediatelyPostLineComment = true; 0710 } 0711 0712 if (isImmediatelyPostReturn) 0713 { 0714 isImmediatelyPostReturn = false; 0715 isCharImmediatelyPostReturn = true; 0716 } 0717 0718 if (isImmediatelyPostThrow) 0719 { 0720 isImmediatelyPostThrow = false; 0721 isCharImmediatelyPostThrow = true; 0722 } 0723 0724 if (isImmediatelyPostNewDelete) 0725 { 0726 isImmediatelyPostNewDelete = false; 0727 isCharImmediatelyPostNewDelete = true; 0728 } 0729 0730 if (isImmediatelyPostOperator) 0731 { 0732 isImmediatelyPostOperator = false; 0733 isCharImmediatelyPostOperator = true; 0734 } 0735 if (isImmediatelyPostTemplate) 0736 { 0737 isImmediatelyPostTemplate = false; 0738 isCharImmediatelyPostTemplate = true; 0739 } 0740 if (isImmediatelyPostPointerOrReference) 0741 { 0742 isImmediatelyPostPointerOrReference = false; 0743 isCharImmediatelyPostPointerOrReference = true; 0744 } 0745 0746 // reset isImmediatelyPostHeader information 0747 if (isImmediatelyPostHeader) 0748 { 0749 // should braces be added 0750 if (currentChar != '{' 0751 && shouldAddBraces 0752 && currentChar != '#' // don't add to preprocessor 0753 && (shouldBreakOneLineStatements || !isHeaderInMultiStatementLine) 0754 && isOkToBreakBlock(braceTypeStack->back())) 0755 { 0756 bool bracesAdded = addBracesToStatement(); 0757 if (bracesAdded && !shouldAddOneLineBraces) 0758 { 0759 size_t firstText = currentLine.find_first_not_of(" \t"); 0760 assert(firstText != string::npos); 0761 if ((int) firstText == charNum || shouldBreakOneLineHeaders) 0762 breakCurrentOneLineBlock = true; 0763 } 0764 } 0765 // should braces be removed 0766 else if (currentChar == '{' && shouldRemoveBraces) 0767 { 0768 bool bracesRemoved = removeBracesFromStatement(); 0769 if (bracesRemoved) 0770 { 0771 shouldRemoveNextClosingBrace = true; 0772 if (isBeforeAnyLineEndComment(charNum)) 0773 spacePadNum--; 0774 else if (shouldBreakOneLineBlocks 0775 || (currentLineBeginsWithBrace 0776 && currentLine.find_first_not_of(" \t") != string::npos)) 0777 shouldBreakLineAtNextChar = true; 0778 continue; 0779 } 0780 } 0781 0782 // break 'else-if' if shouldBreakElseIfs is requested 0783 if (shouldBreakElseIfs 0784 && currentHeader == &AS_ELSE 0785 && isOkToBreakBlock(braceTypeStack->back()) 0786 && !isBeforeAnyComment() 0787 && (shouldBreakOneLineStatements || !isHeaderInMultiStatementLine)) 0788 { 0789 string nextText = peekNextText(currentLine.substr(charNum)); 0790 if (nextText.length() > 0 0791 && isCharPotentialHeader(nextText, 0) 0792 && ASBase::findHeader(nextText, 0, headers) == &AS_IF) 0793 { 0794 isInLineBreak = true; 0795 } 0796 } 0797 0798 // break a header (e.g. if, while, else) from the following statement 0799 if (shouldBreakOneLineHeaders 0800 && peekNextChar() != ' ' 0801 && (shouldBreakOneLineStatements 0802 || (!isHeaderInMultiStatementLine 0803 && !isMultiStatementLine())) 0804 && isOkToBreakBlock(braceTypeStack->back()) 0805 && !isBeforeAnyComment()) 0806 { 0807 if (currentChar == '{') 0808 { 0809 if (!currentLineBeginsWithBrace) 0810 { 0811 if (isOneLineBlockReached(currentLine, charNum) == 3) 0812 isInLineBreak = false; 0813 else 0814 breakCurrentOneLineBlock = true; 0815 } 0816 } 0817 else if (currentHeader == &AS_ELSE) 0818 { 0819 string nextText = peekNextText(currentLine.substr(charNum), true); 0820 if (nextText.length() > 0 0821 && ((isCharPotentialHeader(nextText, 0) 0822 && ASBase::findHeader(nextText, 0, headers) != &AS_IF) 0823 || nextText[0] == '{')) 0824 isInLineBreak = true; 0825 } 0826 else 0827 { 0828 isInLineBreak = true; 0829 } 0830 } 0831 0832 isImmediatelyPostHeader = false; 0833 } 0834 0835 if (passedSemicolon) // need to break the formattedLine 0836 { 0837 passedSemicolon = false; 0838 if (parenStack->back() == 0 && !isCharImmediatelyPostComment && currentChar != ';') // allow ;; 0839 { 0840 // does a one-line block have ending comments? 0841 if (isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)) 0842 { 0843 size_t blockEnd = currentLine.rfind(AS_CLOSE_BRACE); 0844 assert(blockEnd != string::npos); 0845 // move ending comments to this formattedLine 0846 if (isBeforeAnyLineEndComment(blockEnd)) 0847 { 0848 size_t commentStart = currentLine.find_first_not_of(" \t", blockEnd + 1); 0849 assert(commentStart != string::npos); 0850 assert((currentLine.compare(commentStart, 2, "//") == 0) 0851 || (currentLine.compare(commentStart, 2, "/*") == 0)); 0852 formattedLine.append(getIndentLength() - 1, ' '); 0853 // append comment 0854 int charNumSave = charNum; 0855 charNum = commentStart; 0856 while (charNum < (int) currentLine.length()) 0857 { 0858 currentChar = currentLine[charNum]; 0859 if (currentChar == '\t' && shouldConvertTabs) 0860 convertTabToSpaces(); 0861 formattedLine.append(1, currentChar); 0862 ++charNum; 0863 } 0864 size_t commentLength = currentLine.length() - commentStart; 0865 currentLine.erase(commentStart, commentLength); 0866 charNum = charNumSave; 0867 currentChar = currentLine[charNum]; 0868 testForTimeToSplitFormattedLine(); 0869 } 0870 } 0871 isInExecSQL = false; 0872 shouldReparseCurrentChar = true; 0873 if (formattedLine.find_first_not_of(" \t") != string::npos) 0874 isInLineBreak = true; 0875 if (needHeaderOpeningBrace) 0876 { 0877 isCharImmediatelyPostCloseBlock = true; 0878 needHeaderOpeningBrace = false; 0879 } 0880 continue; 0881 } 0882 } 0883 0884 if (passedColon) 0885 { 0886 passedColon = false; 0887 if (parenStack->back() == 0 0888 && !isBeforeAnyComment() 0889 && (formattedLine.find_first_not_of(" \t") != string::npos)) 0890 { 0891 shouldReparseCurrentChar = true; 0892 isInLineBreak = true; 0893 continue; 0894 } 0895 } 0896 0897 // Check if in template declaration, e.g. foo<bar> or foo<bar,fig> 0898 if (!isInTemplate && currentChar == '<') 0899 { 0900 checkIfTemplateOpener(); 0901 } 0902 0903 // Check for break return type 0904 if ((size_t) charNum >= methodBreakCharNum && methodBreakLineNum == 0) 0905 { 0906 if ((size_t) charNum == methodBreakCharNum) 0907 isInLineBreak = true; 0908 methodBreakCharNum = string::npos; 0909 methodBreakLineNum = 0; 0910 } 0911 // Check for attach return type 0912 if ((size_t) charNum >= methodAttachCharNum && methodAttachLineNum == 0) 0913 { 0914 if ((size_t) charNum == methodAttachCharNum) 0915 { 0916 int pa = pointerAlignment; 0917 int ra = referenceAlignment; 0918 int itemAlignment = (previousNonWSChar == '*' || previousNonWSChar == '^') 0919 ? pa : ((ra == REF_SAME_AS_PTR) ? pa : ra); 0920 isInLineBreak = false; 0921 if (previousNonWSChar == '*' || previousNonWSChar == '&' || previousNonWSChar == '^') 0922 { 0923 if (itemAlignment == REF_ALIGN_TYPE) 0924 { 0925 if (formattedLine.length() > 0 0926 && !isWhiteSpace(formattedLine[formattedLine.length() - 1])) 0927 formattedLine.append(1, ' '); 0928 } 0929 else if (itemAlignment == REF_ALIGN_MIDDLE) 0930 { 0931 if (formattedLine.length() > 0 0932 && !isWhiteSpace(formattedLine[formattedLine.length() - 1])) 0933 formattedLine.append(1, ' '); 0934 } 0935 else if (itemAlignment == REF_ALIGN_NAME) 0936 { 0937 if (formattedLine.length() > 0 0938 && isWhiteSpace(formattedLine[formattedLine.length() - 1])) 0939 formattedLine.erase(formattedLine.length() - 1); 0940 } 0941 else 0942 { 0943 if (formattedLine.length() > 1 0944 && !isWhiteSpace(formattedLine[formattedLine.length() - 2])) 0945 formattedLine.append(1, ' '); 0946 } 0947 } 0948 else 0949 formattedLine.append(1, ' '); 0950 } 0951 methodAttachCharNum = string::npos; 0952 methodAttachLineNum = 0; 0953 } 0954 0955 // handle parens 0956 if (currentChar == '(' || currentChar == '[' || (isInTemplate && currentChar == '<')) 0957 { 0958 questionMarkStack->push_back(foundQuestionMark); 0959 foundQuestionMark = false; 0960 parenStack->back()++; 0961 if (currentChar == '[') 0962 { 0963 ++squareBracketCount; 0964 if (getAlignMethodColon() && squareBracketCount == 1 && isCStyle()) 0965 objCColonAlign = findObjCColonAlignment(); 0966 } 0967 } 0968 else if (currentChar == ')' || currentChar == ']' || (isInTemplate && currentChar == '>')) 0969 { 0970 foundPreCommandHeader = false; 0971 parenStack->back()--; 0972 // this can happen in preprocessor directives 0973 if (parenStack->back() < 0) 0974 parenStack->back() = 0; 0975 if (!questionMarkStack->empty()) 0976 { 0977 foundQuestionMark = questionMarkStack->back(); 0978 questionMarkStack->pop_back(); 0979 } 0980 if (isInTemplate && currentChar == '>') 0981 { 0982 templateDepth--; 0983 if (templateDepth == 0) 0984 { 0985 isInTemplate = false; 0986 isImmediatelyPostTemplate = true; 0987 } 0988 } 0989 0990 // check if this parenthesis closes a header, e.g. if (...), while (...) 0991 if (isInHeader && parenStack->back() == 0) 0992 { 0993 isInHeader = false; 0994 isImmediatelyPostHeader = true; 0995 foundQuestionMark = false; 0996 } 0997 if (currentChar == ']') 0998 { 0999 --squareBracketCount; 1000 if (squareBracketCount <= 0) 1001 { 1002 squareBracketCount = 0; 1003 objCColonAlign = 0; 1004 } 1005 } 1006 if (currentChar == ')') 1007 { 1008 foundCastOperator = false; 1009 if (parenStack->back() == 0) 1010 endOfAsmReached = true; 1011 } 1012 } 1013 1014 // handle braces 1015 if (currentChar == '{' || currentChar == '}') 1016 { 1017 // if appendOpeningBrace this was already done for the original brace 1018 if (currentChar == '{' && !appendOpeningBrace) 1019 { 1020 BraceType newBraceType = getBraceType(); 1021 breakCurrentOneLineBlock = false; 1022 foundNamespaceHeader = false; 1023 foundClassHeader = false; 1024 foundStructHeader = false; 1025 foundInterfaceHeader = false; 1026 foundPreDefinitionHeader = false; 1027 foundPreCommandHeader = false; 1028 foundPreCommandMacro = false; 1029 foundTrailingReturnType = false; 1030 isInPotentialCalculation = false; 1031 isInObjCMethodDefinition = false; 1032 isImmediatelyPostObjCMethodPrefix = false; 1033 isInObjCInterface = false; 1034 isInEnum = false; 1035 isJavaStaticConstructor = false; 1036 isCharImmediatelyPostNonInStmt = false; 1037 needHeaderOpeningBrace = false; 1038 shouldKeepLineUnbroken = false; 1039 returnTypeChecked = false; 1040 objCColonAlign = 0; 1041 //assert(methodBreakCharNum == string::npos); // comment out 1042 //assert(methodBreakLineNum == 0); // comment out 1043 methodBreakCharNum = string::npos; 1044 methodBreakLineNum = 0; 1045 methodAttachCharNum = string::npos; 1046 methodAttachLineNum = 0; 1047 1048 isPreviousBraceBlockRelated = !isBraceType(newBraceType, ARRAY_TYPE); 1049 braceTypeStack->emplace_back(newBraceType); 1050 preBraceHeaderStack->emplace_back(currentHeader); 1051 currentHeader = nullptr; 1052 structStack->push_back(isInIndentableStruct); 1053 if (isBraceType(newBraceType, STRUCT_TYPE) && isCStyle()) 1054 isInIndentableStruct = isStructAccessModified(currentLine, charNum); 1055 else 1056 isInIndentableStruct = false; 1057 } 1058 1059 // this must be done before the braceTypeStack is popped 1060 BraceType braceType = braceTypeStack->back(); 1061 bool isOpeningArrayBrace = (isBraceType(braceType, ARRAY_TYPE) 1062 && braceTypeStack->size() >= 2 1063 && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2], ARRAY_TYPE) 1064 ); 1065 1066 if (currentChar == '}') 1067 { 1068 // if a request has been made to append a post block empty line, 1069 // but the block exists immediately before a closing brace, 1070 // then there is no need for the post block empty line. 1071 isAppendPostBlockEmptyLineRequested = false; 1072 if (isInAsm) 1073 endOfAsmReached = true; 1074 isInAsmOneLine = isInQuote = false; 1075 shouldKeepLineUnbroken = false; 1076 squareBracketCount = 0; 1077 1078 if (braceTypeStack->size() > 1) 1079 { 1080 previousBraceType = braceTypeStack->back(); 1081 braceTypeStack->pop_back(); 1082 isPreviousBraceBlockRelated = !isBraceType(braceType, ARRAY_TYPE); 1083 } 1084 else 1085 { 1086 previousBraceType = NULL_TYPE; 1087 isPreviousBraceBlockRelated = false; 1088 } 1089 1090 if (!preBraceHeaderStack->empty()) 1091 { 1092 currentHeader = preBraceHeaderStack->back(); 1093 preBraceHeaderStack->pop_back(); 1094 } 1095 else 1096 currentHeader = nullptr; 1097 1098 if (!structStack->empty()) 1099 { 1100 isInIndentableStruct = structStack->back(); 1101 structStack->pop_back(); 1102 } 1103 else 1104 isInIndentableStruct = false; 1105 1106 if (isNonInStatementArray 1107 && (!isBraceType(braceTypeStack->back(), ARRAY_TYPE) // check previous brace 1108 || peekNextChar() == ';')) // check for "};" added V2.01 1109 isImmediatelyPostNonInStmt = true; 1110 1111 if (!shouldBreakOneLineStatements 1112 && ASBeautifier::getNextWord(currentLine, charNum) == AS_ELSE) 1113 { 1114 // handle special case of "else" at the end of line 1115 size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1); 1116 if (ASBeautifier::peekNextChar(currentLine, nextText + 3) == ' ') 1117 shouldBreakLineAtNextChar = true; 1118 } 1119 } 1120 1121 // format braces 1122 appendOpeningBrace = false; 1123 if (isBraceType(braceType, ARRAY_TYPE)) 1124 { 1125 formatArrayBraces(braceType, isOpeningArrayBrace); 1126 } 1127 else 1128 { 1129 if (currentChar == '{') 1130 formatOpeningBrace(braceType); 1131 else 1132 formatClosingBrace(braceType); 1133 } 1134 continue; 1135 } 1136 1137 if ((((previousCommandChar == '{' && isPreviousBraceBlockRelated) 1138 || ((previousCommandChar == '}' 1139 && !isImmediatelyPostEmptyBlock 1140 && isPreviousBraceBlockRelated 1141 && !isPreviousCharPostComment // Fixes wrongly appended newlines after '}' immediately after comments 1142 && peekNextChar() != ' ' 1143 && !isBraceType(previousBraceType, DEFINITION_TYPE)) 1144 && !isBraceType(braceTypeStack->back(), DEFINITION_TYPE))) 1145 && isOkToBreakBlock(braceTypeStack->back())) 1146 // check for array 1147 || (previousCommandChar == '{' // added 9/30/2010 1148 && isBraceType(braceTypeStack->back(), ARRAY_TYPE) 1149 && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE) 1150 && isNonInStatementArray) 1151 // check for pico one line braces 1152 || (formattingStyle == STYLE_PICO 1153 && (previousCommandChar == '{' && isPreviousBraceBlockRelated) 1154 && isBraceType(braceTypeStack->back(), COMMAND_TYPE) 1155 && isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE) 1156 && braceFormatMode == RUN_IN_MODE) 1157 ) 1158 { 1159 isCharImmediatelyPostOpenBlock = (previousCommandChar == '{'); 1160 isCharImmediatelyPostCloseBlock = (previousCommandChar == '}'); 1161 1162 if (isCharImmediatelyPostOpenBlock 1163 && !isCharImmediatelyPostComment 1164 && !isCharImmediatelyPostLineComment) 1165 { 1166 previousCommandChar = ' '; 1167 1168 if (braceFormatMode == NONE_MODE) 1169 { 1170 if (isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE) 1171 && (isBraceType(braceTypeStack->back(), BREAK_BLOCK_TYPE) 1172 || shouldBreakOneLineBlocks)) 1173 isInLineBreak = true; 1174 else if (currentLineBeginsWithBrace) 1175 formatRunIn(); 1176 else 1177 breakLine(); 1178 } 1179 else if (braceFormatMode == RUN_IN_MODE 1180 && currentChar != '#') 1181 formatRunIn(); 1182 else 1183 isInLineBreak = true; 1184 } 1185 else if (isCharImmediatelyPostCloseBlock 1186 && shouldBreakOneLineStatements 1187 && !isCharImmediatelyPostComment 1188 && ((isLegalNameChar(currentChar) && currentChar != '.') 1189 || currentChar == '+' 1190 || currentChar == '-' 1191 || currentChar == '*' 1192 || currentChar == '&' 1193 || currentChar == '(')) 1194 { 1195 previousCommandChar = ' '; 1196 isInLineBreak = true; 1197 } 1198 } 1199 1200 // reset block handling flags 1201 isImmediatelyPostEmptyBlock = false; 1202 1203 // Objective-C method prefix with no return type 1204 if (isImmediatelyPostObjCMethodPrefix && currentChar != '(') 1205 { 1206 if (shouldPadMethodPrefix || shouldUnPadMethodPrefix) 1207 padObjCMethodPrefix(); 1208 isImmediatelyPostObjCMethodPrefix = false; 1209 } 1210 1211 // look for headers 1212 bool isPotentialHeader = isCharPotentialHeader(currentLine, charNum); 1213 1214 if (isPotentialHeader && !isInTemplate && squareBracketCount == 0) 1215 { 1216 isNonParenHeader = false; 1217 foundClosingHeader = false; 1218 1219 newHeader = findHeader(headers); 1220 1221 // java can have a 'default' not in a switch 1222 if (newHeader == &AS_DEFAULT 1223 && ASBeautifier::peekNextChar( 1224 currentLine, charNum + (*newHeader).length() - 1) != ':') 1225 newHeader = nullptr; 1226 // Qt headers may be variables in C++ 1227 if (isCStyle() 1228 && (newHeader == &AS_FOREVER || newHeader == &AS_FOREACH)) 1229 { 1230 if (currentLine.find_first_of("=;", charNum) != string::npos) 1231 newHeader = nullptr; 1232 } 1233 if (isJavaStyle() 1234 && (newHeader == &AS_SYNCHRONIZED)) 1235 { 1236 // want synchronized statements not synchronized methods 1237 if (!isBraceType(braceTypeStack->back(), COMMAND_TYPE)) 1238 newHeader = nullptr; 1239 } 1240 else if (newHeader == &AS_USING 1241 && ASBeautifier::peekNextChar( 1242 currentLine, charNum + (*newHeader).length() - 1) != '(') 1243 newHeader = nullptr; 1244 1245 if (newHeader != nullptr) 1246 { 1247 foundClosingHeader = isClosingHeader(newHeader); 1248 1249 if (!foundClosingHeader) 1250 { 1251 // these are closing headers 1252 if ((newHeader == &AS_WHILE && currentHeader == &AS_DO) 1253 || (newHeader == &_AS_FINALLY && currentHeader == &_AS_TRY) 1254 || (newHeader == &_AS_EXCEPT && currentHeader == &_AS_TRY)) 1255 foundClosingHeader = true; 1256 // don't append empty block for these related headers 1257 else if (isSharpStyle() 1258 && previousNonWSChar == '}' 1259 && ((newHeader == &AS_SET && currentHeader == &AS_GET) 1260 || (newHeader == &AS_REMOVE && currentHeader == &AS_ADD)) 1261 && isOkToBreakBlock(braceTypeStack->back())) 1262 isAppendPostBlockEmptyLineRequested = false; 1263 } 1264 1265 // TODO: this can be removed in a future release 1266 // version 3.0 - break erroneous attached header from previous versions 1267 if (isSharpStyle() 1268 && ((newHeader == &AS_SET && currentHeader == &AS_GET) 1269 || (newHeader == &AS_REMOVE && currentHeader == &AS_ADD)) 1270 && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE) 1271 && currentLine[currentLine.find_first_not_of(" \t")] == '}') 1272 isInLineBreak = true; 1273 // END TODO 1274 1275 const string* previousHeader = currentHeader; 1276 currentHeader = newHeader; 1277 needHeaderOpeningBrace = true; 1278 1279 // is the previous statement on the same line? 1280 if ((previousNonWSChar == ';' || previousNonWSChar == ':') 1281 && !isInLineBreak 1282 && isOkToBreakBlock(braceTypeStack->back())) 1283 { 1284 // if breaking lines, break the line at the header 1285 // except for multiple 'case' statements on a line 1286 if (maxCodeLength != string::npos 1287 && previousHeader != &AS_CASE) 1288 isInLineBreak = true; 1289 else 1290 isHeaderInMultiStatementLine = true; 1291 } 1292 1293 if (foundClosingHeader && previousNonWSChar == '}') 1294 { 1295 if (isOkToBreakBlock(braceTypeStack->back())) 1296 isLineBreakBeforeClosingHeader(); 1297 1298 // get the adjustment for a comment following the closing header 1299 if (isInLineBreak) 1300 nextLineSpacePadNum = getNextLineCommentAdjustment(); 1301 else 1302 spacePadNum = getCurrentLineCommentAdjustment(); 1303 } 1304 1305 // check if the found header is non-paren header 1306 isNonParenHeader = findHeader(nonParenHeaders) != nullptr; 1307 1308 if (isNonParenHeader 1309 && (currentHeader == &AS_CATCH 1310 || currentHeader == &AS_CASE)) 1311 { 1312 int startChar = charNum + currentHeader->length() - 1; 1313 if (ASBeautifier::peekNextChar(currentLine, startChar) == '(') 1314 isNonParenHeader = false; 1315 } 1316 1317 // join 'else if' statements 1318 if (currentHeader == &AS_IF 1319 && previousHeader == &AS_ELSE 1320 && isInLineBreak 1321 && !shouldBreakElseIfs 1322 && !isCharImmediatelyPostLineComment 1323 && !isImmediatelyPostPreprocessor) 1324 { 1325 // 'else' must be last thing on the line 1326 size_t start = formattedLine.length() >= 6 ? formattedLine.length() - 6 : 0; 1327 if (formattedLine.find(AS_ELSE, start) != string::npos) 1328 { 1329 appendSpacePad(); 1330 isInLineBreak = false; 1331 } 1332 } 1333 1334 appendSequence(*currentHeader); 1335 goForward(currentHeader->length() - 1); 1336 // if a paren-header is found add a space after it, if needed 1337 // this checks currentLine, appendSpacePad() checks formattedLine 1338 // in 'case' and C# 'catch' can be either a paren or non-paren header 1339 if (shouldPadHeader 1340 && !isNonParenHeader 1341 && charNum < (int) currentLine.length() - 1 && !isWhiteSpace(currentLine[charNum + 1])) 1342 appendSpacePad(); 1343 1344 // Signal that a header has been reached 1345 // *** But treat a closing while() (as in do...while) 1346 // as if it were NOT a header since a closing while() 1347 // should never have a block after it! 1348 if (currentHeader != &AS_CASE && currentHeader != &AS_DEFAULT 1349 && !(foundClosingHeader && currentHeader == &AS_WHILE)) 1350 { 1351 isInHeader = true; 1352 1353 // in C# 'catch' and 'delegate' can be a paren or non-paren header 1354 if (isNonParenHeader && !isSharpStyleWithParen(currentHeader)) 1355 { 1356 isImmediatelyPostHeader = true; 1357 isInHeader = false; 1358 } 1359 } 1360 1361 if (shouldBreakBlocks 1362 && isOkToBreakBlock(braceTypeStack->back()) 1363 && !isHeaderInMultiStatementLine) 1364 { 1365 if (previousHeader == nullptr 1366 && !foundClosingHeader 1367 && !isCharImmediatelyPostOpenBlock 1368 && !isImmediatelyPostCommentOnly) 1369 { 1370 isPrependPostBlockEmptyLineRequested = true; 1371 } 1372 1373 if (isClosingHeader(currentHeader) 1374 || foundClosingHeader) 1375 { 1376 isPrependPostBlockEmptyLineRequested = false; 1377 } 1378 1379 if (shouldBreakClosingHeaderBlocks 1380 && isCharImmediatelyPostCloseBlock 1381 && !isImmediatelyPostCommentOnly 1382 && !(currentHeader == &AS_WHILE // do-while 1383 && foundClosingHeader)) 1384 { 1385 isPrependPostBlockEmptyLineRequested = true; 1386 } 1387 } 1388 1389 if (currentHeader == &AS_CASE 1390 || currentHeader == &AS_DEFAULT) 1391 isInCase = true; 1392 1393 continue; 1394 } 1395 else if ((newHeader = findHeader(preDefinitionHeaders)) != nullptr 1396 && parenStack->back() == 0 1397 && !isInEnum) // not C++11 enum class 1398 { 1399 if (newHeader == &AS_NAMESPACE || newHeader == &AS_MODULE) 1400 foundNamespaceHeader = true; 1401 if (newHeader == &AS_CLASS) 1402 foundClassHeader = true; 1403 if (newHeader == &AS_STRUCT) 1404 foundStructHeader = true; 1405 if (newHeader == &AS_INTERFACE && !foundNamespaceHeader && !foundClassHeader) 1406 foundInterfaceHeader = true; 1407 foundPreDefinitionHeader = true; 1408 appendSequence(*newHeader); 1409 goForward(newHeader->length() - 1); 1410 1411 continue; 1412 } 1413 else if ((newHeader = findHeader(preCommandHeaders)) != nullptr) 1414 { 1415 // must be after function arguments 1416 if (previousNonWSChar == ')') 1417 foundPreCommandHeader = true; 1418 } 1419 else if ((newHeader = findHeader(castOperators)) != nullptr) 1420 { 1421 foundCastOperator = true; 1422 appendSequence(*newHeader); 1423 goForward(newHeader->length() - 1); 1424 continue; 1425 } 1426 } // (isPotentialHeader && !isInTemplate) 1427 1428 if (isInLineBreak) // OK to break line here 1429 { 1430 breakLine(); 1431 if (isInVirginLine) // adjust for the first line 1432 { 1433 lineCommentNoBeautify = lineCommentNoIndent; 1434 lineCommentNoIndent = false; 1435 if (isImmediatelyPostPreprocessor) 1436 { 1437 isInIndentablePreproc = isIndentableProprocessor; 1438 isIndentableProprocessor = false; 1439 } 1440 } 1441 } 1442 1443 if (previousNonWSChar == '}' || currentChar == ';') 1444 { 1445 if (currentChar == ';') 1446 { 1447 squareBracketCount = 0; 1448 //assert(methodBreakCharNum == string::npos); // comment out 1449 //assert(methodBreakLineNum == 0); // comment out 1450 methodBreakCharNum = string::npos; 1451 methodBreakLineNum = 0; 1452 methodAttachCharNum = string::npos; 1453 methodAttachLineNum = 0; 1454 1455 if (((shouldBreakOneLineStatements 1456 || isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)) 1457 && isOkToBreakBlock(braceTypeStack->back())) 1458 && !(attachClosingBraceMode && peekNextChar() == '}')) 1459 { 1460 passedSemicolon = true; 1461 } 1462 else if (!shouldBreakOneLineStatements 1463 && ASBeautifier::getNextWord(currentLine, charNum) == AS_ELSE) 1464 { 1465 // handle special case of "else" at the end of line 1466 size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1); 1467 if (ASBeautifier::peekNextChar(currentLine, nextText + 3) == ' ') 1468 passedSemicolon = true; 1469 } 1470 1471 if (shouldBreakBlocks 1472 && currentHeader != nullptr 1473 && currentHeader != &AS_CASE 1474 && currentHeader != &AS_DEFAULT 1475 && !isHeaderInMultiStatementLine 1476 && parenStack->back() == 0) 1477 { 1478 isAppendPostBlockEmptyLineRequested = true; 1479 } 1480 } 1481 if (currentChar != ';' 1482 || (needHeaderOpeningBrace && parenStack->back() == 0)) 1483 currentHeader = nullptr; 1484 1485 resetEndOfStatement(); 1486 } 1487 1488 if (currentChar == ':' 1489 && previousChar != ':' // not part of '::' 1490 && peekNextChar() != ':') // not part of '::' 1491 { 1492 if (isInCase) 1493 { 1494 isInCase = false; 1495 if (shouldBreakOneLineStatements) 1496 passedColon = true; 1497 } 1498 else if (isCStyle() // for C/C++ only 1499 && isOkToBreakBlock(braceTypeStack->back()) 1500 && shouldBreakOneLineStatements 1501 && !foundQuestionMark // not in a ?: sequence 1502 && !foundPreDefinitionHeader // not in a definition block 1503 && previousCommandChar != ')' // not after closing paren of a method header 1504 && !foundPreCommandHeader // not after a 'noexcept' 1505 && squareBracketCount == 0 // not in objC method call 1506 && !isInObjCMethodDefinition // not objC '-' or '+' method 1507 && !isInObjCInterface // not objC @interface 1508 && !isInObjCSelector // not objC @selector 1509 && !isDigit(peekNextChar()) // not a bit field 1510 && !isInEnum // not an enum with a base type 1511 && !isInAsm // not in extended assembler 1512 && !isInAsmOneLine // not in extended assembler 1513 && !isInAsmBlock) // not in extended assembler 1514 { 1515 passedColon = true; 1516 } 1517 1518 if (isCStyle() 1519 && (squareBracketCount > 0 || isInObjCMethodDefinition || isInObjCSelector) 1520 && !foundQuestionMark) // not in a ?: sequence 1521 { 1522 isImmediatelyPostObjCMethodPrefix = false; 1523 isInObjCReturnType = false; 1524 isInObjCParam = true; 1525 if (shouldPadMethodColon) 1526 padObjCMethodColon(); 1527 } 1528 1529 if (isInObjCInterface) 1530 { 1531 appendSpacePad(); 1532 if ((int) currentLine.length() > charNum + 1 1533 && !isWhiteSpace(currentLine[charNum + 1])) 1534 currentLine.insert(charNum + 1, " "); 1535 } 1536 1537 if (isClassInitializer()) 1538 isInClassInitializer = true; 1539 } 1540 1541 if (currentChar == '?') 1542 foundQuestionMark = true; 1543 1544 if (isPotentialHeader && !isInTemplate) 1545 { 1546 if (findKeyword(currentLine, charNum, AS_NEW) 1547 || findKeyword(currentLine, charNum, AS_DELETE)) 1548 { 1549 isInPotentialCalculation = false; 1550 isImmediatelyPostNewDelete = true; 1551 } 1552 1553 if (findKeyword(currentLine, charNum, AS_RETURN)) 1554 { 1555 isInPotentialCalculation = true; 1556 isImmediatelyPostReturn = true; // return is the same as an = sign 1557 } 1558 1559 if (findKeyword(currentLine, charNum, AS_OPERATOR)) 1560 isImmediatelyPostOperator = true; 1561 1562 if (findKeyword(currentLine, charNum, AS_ENUM)) 1563 { 1564 size_t firstNum = currentLine.find_first_of("(){},/"); 1565 if (firstNum == string::npos 1566 || currentLine[firstNum] == '{' 1567 || currentLine[firstNum] == '/') 1568 isInEnum = true; 1569 } 1570 1571 if (isCStyle() 1572 && findKeyword(currentLine, charNum, AS_THROW) 1573 && previousCommandChar != ')' 1574 && !foundPreCommandHeader) // 'const' throw() 1575 isImmediatelyPostThrow = true; 1576 1577 if (isCStyle() && findKeyword(currentLine, charNum, AS_EXTERN) && isExternC()) 1578 isInExternC = true; 1579 1580 if (isCStyle() && findKeyword(currentLine, charNum, AS_AUTO) 1581 && (isBraceType(braceTypeStack->back(), NULL_TYPE) 1582 || isBraceType(braceTypeStack->back(), DEFINITION_TYPE))) 1583 foundTrailingReturnType = true; 1584 1585 // check for break/attach return type 1586 if (shouldBreakReturnType || shouldBreakReturnTypeDecl 1587 || shouldAttachReturnType || shouldAttachReturnTypeDecl) 1588 { 1589 if ((isBraceType(braceTypeStack->back(), NULL_TYPE) 1590 || isBraceType(braceTypeStack->back(), DEFINITION_TYPE)) 1591 && !returnTypeChecked 1592 && !foundNamespaceHeader 1593 && !foundClassHeader 1594 && !isInObjCMethodDefinition 1595 // bypass objective-C and java @ character 1596 && charNum == (int) currentLine.find_first_not_of(" \t") 1597 && !(isCStyle() && isCharPotentialHeader(currentLine, charNum) 1598 && (findKeyword(currentLine, charNum, AS_PUBLIC) 1599 || findKeyword(currentLine, charNum, AS_PRIVATE) 1600 || findKeyword(currentLine, charNum, AS_PROTECTED)))) 1601 { 1602 findReturnTypeSplitPoint(currentLine); 1603 returnTypeChecked = true; 1604 } 1605 } 1606 1607 // Objective-C NSException macros are preCommandHeaders 1608 if (isCStyle() && findKeyword(currentLine, charNum, AS_NS_DURING)) 1609 foundPreCommandMacro = true; 1610 if (isCStyle() && findKeyword(currentLine, charNum, AS_NS_HANDLER)) 1611 foundPreCommandMacro = true; 1612 1613 if (isCStyle() && isExecSQL(currentLine, charNum)) 1614 isInExecSQL = true; 1615 1616 if (isCStyle()) 1617 { 1618 if (findKeyword(currentLine, charNum, AS_ASM) 1619 || findKeyword(currentLine, charNum, AS__ASM__)) 1620 { 1621 isInAsm = true; 1622 } 1623 else if (findKeyword(currentLine, charNum, AS_MS_ASM) // microsoft specific 1624 || findKeyword(currentLine, charNum, AS_MS__ASM)) 1625 { 1626 int index = 4; 1627 if (peekNextChar() == '_') // check for __asm 1628 index = 5; 1629 1630 char peekedChar = ASBase::peekNextChar(currentLine, charNum + index); 1631 if (peekedChar == '{' || peekedChar == ' ') 1632 isInAsmBlock = true; 1633 else 1634 isInAsmOneLine = true; 1635 } 1636 } 1637 1638 if (isJavaStyle() 1639 && (findKeyword(currentLine, charNum, AS_STATIC) 1640 && isNextCharOpeningBrace(charNum + 6))) 1641 isJavaStaticConstructor = true; 1642 1643 if (isSharpStyle() 1644 && (findKeyword(currentLine, charNum, AS_DELEGATE) 1645 || findKeyword(currentLine, charNum, AS_UNCHECKED))) 1646 isSharpDelegate = true; 1647 1648 // append the entire name 1649 string name = getCurrentWord(currentLine, charNum); 1650 // must pad the 'and' and 'or' operators if required 1651 if (name == "and" || name == "or") 1652 { 1653 if (shouldPadOperators && previousNonWSChar != ':') 1654 { 1655 appendSpacePad(); 1656 appendOperator(name); 1657 goForward(name.length() - 1); 1658 if (!isBeforeAnyComment() 1659 && !(currentLine.compare(charNum + 1, 1, AS_SEMICOLON) == 0) 1660 && !(currentLine.compare(charNum + 1, 2, AS_SCOPE_RESOLUTION) == 0)) 1661 appendSpaceAfter(); 1662 } 1663 else 1664 { 1665 appendOperator(name); 1666 goForward(name.length() - 1); 1667 } 1668 } 1669 else 1670 { 1671 appendSequence(name); 1672 goForward(name.length() - 1); 1673 } 1674 1675 continue; 1676 1677 } // (isPotentialHeader && !isInTemplate) 1678 1679 // determine if this is an Objective-C statement 1680 1681 if (currentChar == '@' 1682 && isCStyle() 1683 && (int) currentLine.length() > charNum + 1 1684 && !isWhiteSpace(currentLine[charNum + 1]) 1685 && isCharPotentialHeader(currentLine, charNum + 1) 1686 && findKeyword(currentLine, charNum + 1, AS_INTERFACE) 1687 && isBraceType(braceTypeStack->back(), NULL_TYPE)) 1688 { 1689 isInObjCInterface = true; 1690 string name = '@' + AS_INTERFACE; 1691 appendSequence(name); 1692 goForward(name.length() - 1); 1693 continue; 1694 } 1695 else if (currentChar == '@' 1696 && isCStyle() 1697 && (int) currentLine.length() > charNum + 1 1698 && !isWhiteSpace(currentLine[charNum + 1]) 1699 && isCharPotentialHeader(currentLine, charNum + 1) 1700 && findKeyword(currentLine, charNum + 1, AS_SELECTOR)) 1701 { 1702 isInObjCSelector = true; 1703 string name = '@' + AS_SELECTOR; 1704 appendSequence(name); 1705 goForward(name.length() - 1); 1706 continue; 1707 } 1708 else if ((currentChar == '-' || currentChar == '+') 1709 && isCStyle() 1710 && (int) currentLine.find_first_not_of(" \t") == charNum 1711 && !isInPotentialCalculation 1712 && !isInObjCMethodDefinition 1713 && (isBraceType(braceTypeStack->back(), NULL_TYPE) 1714 || (isBraceType(braceTypeStack->back(), EXTERN_TYPE)))) 1715 { 1716 isInObjCMethodDefinition = true; 1717 isImmediatelyPostObjCMethodPrefix = true; 1718 isInObjCParam = false; 1719 isInObjCInterface = false; 1720 if (getAlignMethodColon()) 1721 objCColonAlign = findObjCColonAlignment(); 1722 appendCurrentChar(); 1723 continue; 1724 } 1725 1726 // determine if this is a potential calculation 1727 1728 bool isPotentialOperator = isCharPotentialOperator(currentChar); 1729 newHeader = nullptr; 1730 1731 if (isPotentialOperator) 1732 { 1733 newHeader = findOperator(operators); 1734 1735 // check for Java ? wildcard 1736 if (newHeader != nullptr 1737 && newHeader == &AS_GCC_MIN_ASSIGN 1738 && isJavaStyle() 1739 && isInTemplate) 1740 newHeader = nullptr; 1741 1742 if (newHeader != nullptr) 1743 { 1744 if (newHeader == &AS_LAMBDA) 1745 foundPreCommandHeader = true; 1746 1747 // correct mistake of two >> closing a template 1748 if (isInTemplate && (newHeader == &AS_GR_GR || newHeader == &AS_GR_GR_GR)) 1749 newHeader = &AS_GR; 1750 1751 if (!isInPotentialCalculation) 1752 { 1753 // must determine if newHeader is an assignment operator 1754 // do NOT use findOperator - the length must be exact!!! 1755 if (find(begin(*assignmentOperators), end(*assignmentOperators), newHeader) 1756 != end(*assignmentOperators)) 1757 { 1758 foundPreCommandHeader = false; 1759 char peekedChar = peekNextChar(); 1760 isInPotentialCalculation = !(newHeader == &AS_EQUAL && peekedChar == '*') 1761 && !(newHeader == &AS_EQUAL && peekedChar == '&') 1762 && !isCharImmediatelyPostOperator; 1763 } 1764 } 1765 } 1766 } 1767 1768 // process pointers and references 1769 // check newHeader to eliminate things like '&&' sequence 1770 if (newHeader != nullptr && !isJavaStyle() 1771 && (newHeader == &AS_MULT 1772 || newHeader == &AS_BIT_AND 1773 || newHeader == &AS_BIT_XOR 1774 || newHeader == &AS_AND) 1775 && isPointerOrReference()) 1776 { 1777 if (!isDereferenceOrAddressOf() && !isOperatorPaddingDisabled()) 1778 formatPointerOrReference(); 1779 else 1780 { 1781 appendOperator(*newHeader); 1782 goForward(newHeader->length() - 1); 1783 } 1784 isImmediatelyPostPointerOrReference = true; 1785 continue; 1786 } 1787 1788 if (shouldPadOperators && newHeader != nullptr && !isOperatorPaddingDisabled()) 1789 { 1790 padOperators(newHeader); 1791 continue; 1792 } 1793 1794 // remove spaces before commas 1795 if (currentChar == ',') 1796 { 1797 const size_t len = formattedLine.length(); 1798 size_t lastText = formattedLine.find_last_not_of(' '); 1799 if (lastText != string::npos && lastText < len - 1) 1800 { 1801 formattedLine.resize(lastText + 1); 1802 int size_diff = len - (lastText + 1); 1803 spacePadNum -= size_diff; 1804 } 1805 } 1806 1807 // pad commas and semi-colons 1808 if (currentChar == ';' 1809 || (currentChar == ',' && (shouldPadOperators || shouldPadCommas))) 1810 { 1811 char nextChar = ' '; 1812 if (charNum + 1 < (int) currentLine.length()) 1813 nextChar = currentLine[charNum + 1]; 1814 if (!isWhiteSpace(nextChar) 1815 && nextChar != '}' 1816 && nextChar != ')' 1817 && nextChar != ']' 1818 && nextChar != '>' 1819 && nextChar != ';' 1820 && !isBeforeAnyComment() 1821 /* && !(isBraceType(braceTypeStack->back(), ARRAY_TYPE)) */ 1822 ) 1823 { 1824 appendCurrentChar(); 1825 appendSpaceAfter(); 1826 continue; 1827 } 1828 } 1829 1830 // pad parens 1831 if (currentChar == '(' || currentChar == ')') 1832 { 1833 if (currentChar == '(') 1834 { 1835 if (shouldPadHeader 1836 && (isCharImmediatelyPostReturn 1837 || isCharImmediatelyPostThrow 1838 || isCharImmediatelyPostNewDelete)) 1839 appendSpacePad(); 1840 } 1841 1842 if (shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens || shouldPadFirstParen) 1843 padParens(); 1844 else 1845 appendCurrentChar(); 1846 1847 if (isInObjCMethodDefinition) 1848 { 1849 if (currentChar == '(' && isImmediatelyPostObjCMethodPrefix) 1850 { 1851 if (shouldPadMethodPrefix || shouldUnPadMethodPrefix) 1852 padObjCMethodPrefix(); 1853 isImmediatelyPostObjCMethodPrefix = false; 1854 isInObjCReturnType = true; 1855 } 1856 else if (currentChar == ')' && isInObjCReturnType) 1857 { 1858 if (shouldPadReturnType || shouldUnPadReturnType) 1859 padObjCReturnType(); 1860 isInObjCReturnType = false; 1861 } 1862 else if (isInObjCParam 1863 && (shouldPadParamType || shouldUnPadParamType)) 1864 padObjCParamType(); 1865 } 1866 continue; 1867 } 1868 1869 // bypass the entire operator 1870 if (newHeader != nullptr) 1871 { 1872 appendOperator(*newHeader); 1873 goForward(newHeader->length() - 1); 1874 continue; 1875 } 1876 1877 appendCurrentChar(); 1878 1879 } // end of while loop * end of while loop * end of while loop * end of while loop 1880 1881 // return a beautified (i.e. correctly indented) line. 1882 1883 string beautifiedLine; 1884 size_t readyFormattedLineLength = trim(readyFormattedLine).length(); 1885 bool isInNamespace = isBraceType(braceTypeStack->back(), NAMESPACE_TYPE); 1886 1887 if (prependEmptyLine // prepend a blank line before this formatted line 1888 && readyFormattedLineLength > 0 1889 && previousReadyFormattedLineLength > 0) 1890 { 1891 isLineReady = true; // signal a waiting readyFormattedLine 1892 beautifiedLine = beautify(""); 1893 previousReadyFormattedLineLength = 0; 1894 // call the enhancer for new empty lines 1895 enhancer->enhance(beautifiedLine, isInNamespace, isInPreprocessorBeautify, isInBeautifySQL); 1896 } 1897 else // format the current formatted line 1898 { 1899 isLineReady = false; 1900 runInIndentContinuation = runInIndentChars; 1901 beautifiedLine = beautify(readyFormattedLine); 1902 previousReadyFormattedLineLength = readyFormattedLineLength; 1903 // the enhancer is not called for no-indent line comments 1904 if (!lineCommentNoBeautify && !isFormattingModeOff) 1905 enhancer->enhance(beautifiedLine, isInNamespace, isInPreprocessorBeautify, isInBeautifySQL); 1906 runInIndentChars = 0; 1907 lineCommentNoBeautify = lineCommentNoIndent; 1908 lineCommentNoIndent = false; 1909 isInIndentablePreproc = isIndentableProprocessor; 1910 isIndentableProprocessor = false; 1911 isElseHeaderIndent = elseHeaderFollowsComments; 1912 isCaseHeaderCommentIndent = caseHeaderFollowsComments; 1913 objCColonAlignSubsequent = objCColonAlign; 1914 if (isCharImmediatelyPostNonInStmt) 1915 { 1916 isNonInStatementArray = false; 1917 isCharImmediatelyPostNonInStmt = false; 1918 } 1919 isInPreprocessorBeautify = isInPreprocessor; // used by ASEnhancer 1920 isInBeautifySQL = isInExecSQL; // used by ASEnhancer 1921 } 1922 1923 prependEmptyLine = false; 1924 assert(computeChecksumOut(beautifiedLine)); 1925 return beautifiedLine; 1926 } 1927 1928 /** 1929 * check if there are any indented lines ready to be read by nextLine() 1930 * 1931 * @return are there any indented lines ready? 1932 */ 1933 bool ASFormatter::hasMoreLines() const 1934 { 1935 return !endOfCodeReached; 1936 } 1937 1938 /** 1939 * comparison function for BraceType enum 1940 */ 1941 bool ASFormatter::isBraceType(BraceType a, BraceType b) const 1942 { 1943 if (a == NULL_TYPE || b == NULL_TYPE) 1944 return (a == b); 1945 return ((a & b) == b); 1946 } 1947 1948 /** 1949 * set the formatting style. 1950 * 1951 * @param style the formatting style. 1952 */ 1953 void ASFormatter::setFormattingStyle(FormatStyle style) 1954 { 1955 formattingStyle = style; 1956 } 1957 1958 /** 1959 * set the add braces mode. 1960 * options: 1961 * true braces added to headers for single line statements. 1962 * false braces NOT added to headers for single line statements. 1963 * 1964 * @param state the add braces state. 1965 */ 1966 void ASFormatter::setAddBracesMode(bool state) 1967 { 1968 shouldAddBraces = state; 1969 } 1970 1971 /** 1972 * set the add one line braces mode. 1973 * options: 1974 * true one line braces added to headers for single line statements. 1975 * false one line braces NOT added to headers for single line statements. 1976 * 1977 * @param state the add one line braces state. 1978 */ 1979 void ASFormatter::setAddOneLineBracesMode(bool state) 1980 { 1981 shouldAddBraces = state; 1982 shouldAddOneLineBraces = state; 1983 } 1984 1985 /** 1986 * set the remove braces mode. 1987 * options: 1988 * true braces removed from headers for single line statements. 1989 * false braces NOT removed from headers for single line statements. 1990 * 1991 * @param state the remove braces state. 1992 */ 1993 void ASFormatter::setRemoveBracesMode(bool state) 1994 { 1995 shouldRemoveBraces = state; 1996 } 1997 1998 // retained for compatibility with release 2.06 1999 // "Brackets" have been changed to "Braces" in 3.0 2000 // it is referenced only by the old "bracket" options 2001 void ASFormatter::setAddBracketsMode(bool state) 2002 { 2003 setAddBracesMode(state); 2004 } 2005 2006 // retained for compatibility with release 2.06 2007 // "Brackets" have been changed to "Braces" in 3.0 2008 // it is referenced only by the old "bracket" options 2009 void ASFormatter::setAddOneLineBracketsMode(bool state) 2010 { 2011 setAddOneLineBracesMode(state); 2012 } 2013 2014 // retained for compatibility with release 2.06 2015 // "Brackets" have been changed to "Braces" in 3.0 2016 // it is referenced only by the old "bracket" options 2017 void ASFormatter::setRemoveBracketsMode(bool state) 2018 { 2019 setRemoveBracesMode(state); 2020 } 2021 2022 // retained for compatibility with release 2.06 2023 // "Brackets" have been changed to "Braces" in 3.0 2024 // it is referenced only by the old "bracket" options 2025 void ASFormatter::setBreakClosingHeaderBracketsMode(bool state) 2026 { 2027 setBreakClosingHeaderBracesMode(state); 2028 } 2029 2030 /** 2031 * set the brace formatting mode. 2032 * options: 2033 * 2034 * @param mode the brace formatting mode. 2035 */ 2036 void ASFormatter::setBraceFormatMode(BraceMode mode) 2037 { 2038 braceFormatMode = mode; 2039 } 2040 2041 /** 2042 * set 'break after' mode for maximum code length 2043 * 2044 * @param state the 'break after' mode. 2045 */ 2046 void ASFormatter::setBreakAfterMode(bool state) 2047 { 2048 shouldBreakLineAfterLogical = state; 2049 } 2050 2051 /** 2052 * set closing header brace breaking mode 2053 * options: 2054 * true braces just before closing headers (e.g. 'else', 'catch') 2055 * will be broken, even if standard braces are attached. 2056 * false closing header braces will be treated as standard braces. 2057 * 2058 * @param state the closing header brace breaking mode. 2059 */ 2060 void ASFormatter::setBreakClosingHeaderBracesMode(bool state) 2061 { 2062 shouldBreakClosingHeaderBraces = state; 2063 } 2064 2065 /** 2066 * set 'else if()' breaking mode 2067 * options: 2068 * true 'else' headers will be broken from their succeeding 'if' headers. 2069 * false 'else' headers will be attached to their succeeding 'if' headers. 2070 * 2071 * @param state the 'else if()' breaking mode. 2072 */ 2073 void ASFormatter::setBreakElseIfsMode(bool state) 2074 { 2075 shouldBreakElseIfs = state; 2076 } 2077 2078 /** 2079 * set comma padding mode. 2080 * options: 2081 * true statement commas and semicolons will be padded with spaces around them. 2082 * false statement commas and semicolons will not be padded. 2083 * 2084 * @param state the padding mode. 2085 */ 2086 void ASFormatter::setCommaPaddingMode(bool state) 2087 { 2088 shouldPadCommas = state; 2089 } 2090 2091 /** 2092 * set maximum code length 2093 * 2094 * @param max the maximum code length. 2095 */ 2096 void ASFormatter::setMaxCodeLength(int max) 2097 { 2098 maxCodeLength = max; 2099 } 2100 2101 /** 2102 * set operator padding mode. 2103 * options: 2104 * true statement operators will be padded with spaces around them. 2105 * false statement operators will not be padded. 2106 * 2107 * @param state the padding mode. 2108 */ 2109 void ASFormatter::setOperatorPaddingMode(bool state) 2110 { 2111 shouldPadOperators = state; 2112 } 2113 2114 /** 2115 * set parenthesis outside padding mode. 2116 * options: 2117 * true statement parentheses will be padded with spaces around them. 2118 * false statement parentheses will not be padded. 2119 * 2120 * @param state the padding mode. 2121 */ 2122 void ASFormatter::setParensOutsidePaddingMode(bool state) 2123 { 2124 shouldPadParensOutside = state; 2125 } 2126 2127 /** 2128 * set parenthesis inside padding mode. 2129 * options: 2130 * true statement parenthesis will be padded with spaces around them. 2131 * false statement parenthesis will not be padded. 2132 * 2133 * @param state the padding mode. 2134 */ 2135 void ASFormatter::setParensInsidePaddingMode(bool state) 2136 { 2137 shouldPadParensInside = state; 2138 } 2139 2140 /** 2141 * set padding mode before one or more open parentheses. 2142 * options: 2143 * true first open parenthesis will be padded with a space before. 2144 * false first open parenthesis will not be padded. 2145 * 2146 * @param state the padding mode. 2147 */ 2148 void ASFormatter::setParensFirstPaddingMode(bool state) 2149 { 2150 shouldPadFirstParen = state; 2151 } 2152 2153 /** 2154 * set header padding mode. 2155 * options: 2156 * true headers will be padded with spaces around them. 2157 * false headers will not be padded. 2158 * 2159 * @param state the padding mode. 2160 */ 2161 void ASFormatter::setParensHeaderPaddingMode(bool state) 2162 { 2163 shouldPadHeader = state; 2164 } 2165 2166 /** 2167 * set parenthesis unpadding mode. 2168 * options: 2169 * true statement parenthesis will be unpadded with spaces removed around them. 2170 * false statement parenthesis will not be unpadded. 2171 * 2172 * @param state the padding mode. 2173 */ 2174 void ASFormatter::setParensUnPaddingMode(bool state) 2175 { 2176 shouldUnPadParens = state; 2177 } 2178 2179 /** 2180 * set the state of the preprocessor indentation option. 2181 * If true, #ifdef blocks at level 0 will be indented. 2182 * 2183 * @param state state of option. 2184 */ 2185 void ASFormatter::setPreprocBlockIndent(bool state) 2186 { 2187 shouldIndentPreprocBlock = state; 2188 } 2189 2190 /** 2191 * Set strip comment prefix mode. 2192 * options: 2193 * true strip leading '*' in a comment. 2194 * false leading '*' in a comment will be left unchanged. 2195 * 2196 * @param state the strip comment prefix mode. 2197 */ 2198 void ASFormatter::setStripCommentPrefix(bool state) 2199 { 2200 shouldStripCommentPrefix = state; 2201 } 2202 2203 /** 2204 * set objective-c '-' or '+' class prefix padding mode. 2205 * options: 2206 * true class prefix will be padded a spaces after them. 2207 * false class prefix will be left unchanged. 2208 * 2209 * @param state the padding mode. 2210 */ 2211 void ASFormatter::setMethodPrefixPaddingMode(bool state) 2212 { 2213 shouldPadMethodPrefix = state; 2214 } 2215 2216 /** 2217 * set objective-c '-' or '+' class prefix unpadding mode. 2218 * options: 2219 * true class prefix will be unpadded with spaces after them removed. 2220 * false class prefix will left unchanged. 2221 * 2222 * @param state the unpadding mode. 2223 */ 2224 void ASFormatter::setMethodPrefixUnPaddingMode(bool state) 2225 { 2226 shouldUnPadMethodPrefix = state; 2227 } 2228 2229 // set objective-c '-' or '+' return type padding mode. 2230 void ASFormatter::setReturnTypePaddingMode(bool state) 2231 { 2232 shouldPadReturnType = state; 2233 } 2234 2235 // set objective-c '-' or '+' return type unpadding mode. 2236 void ASFormatter::setReturnTypeUnPaddingMode(bool state) 2237 { 2238 shouldUnPadReturnType = state; 2239 } 2240 2241 // set objective-c method parameter type padding mode. 2242 void ASFormatter::setParamTypePaddingMode(bool state) 2243 { 2244 shouldPadParamType = state; 2245 } 2246 2247 // set objective-c method parameter type unpadding mode. 2248 void ASFormatter::setParamTypeUnPaddingMode(bool state) 2249 { 2250 shouldUnPadParamType = state; 2251 } 2252 2253 /** 2254 * set objective-c method colon padding mode. 2255 * 2256 * @param mode objective-c colon padding mode. 2257 */ 2258 void ASFormatter::setObjCColonPaddingMode(ObjCColonPad mode) 2259 { 2260 shouldPadMethodColon = true; 2261 objCColonPadMode = mode; 2262 } 2263 2264 /** 2265 * set option to attach closing braces 2266 * 2267 * @param state true = attach, false = don't attach. 2268 */ 2269 void ASFormatter::setAttachClosingBraceMode(bool state) 2270 { 2271 attachClosingBraceMode = state; 2272 } 2273 2274 /** 2275 * set option to attach class braces 2276 * 2277 * @param state true = attach, false = use style default. 2278 */ 2279 void ASFormatter::setAttachClass(bool state) 2280 { 2281 shouldAttachClass = state; 2282 } 2283 2284 /** 2285 * set option to attach extern "C" braces 2286 * 2287 * @param state true = attach, false = use style default. 2288 */ 2289 void ASFormatter::setAttachExternC(bool state) 2290 { 2291 shouldAttachExternC = state; 2292 } 2293 2294 /** 2295 * set option to attach namespace braces 2296 * 2297 * @param state true = attach, false = use style default. 2298 */ 2299 void ASFormatter::setAttachNamespace(bool state) 2300 { 2301 shouldAttachNamespace = state; 2302 } 2303 2304 /** 2305 * set option to attach inline braces 2306 * 2307 * @param state true = attach, false = use style default. 2308 */ 2309 void ASFormatter::setAttachInline(bool state) 2310 { 2311 shouldAttachInline = state; 2312 } 2313 2314 void ASFormatter::setAttachClosingWhile(bool state) 2315 { 2316 shouldAttachClosingWhile = state; 2317 } 2318 2319 /** 2320 * set option to break/not break one-line blocks 2321 * 2322 * @param state true = break, false = don't break. 2323 */ 2324 void ASFormatter::setBreakOneLineBlocksMode(bool state) 2325 { 2326 shouldBreakOneLineBlocks = state; 2327 } 2328 2329 /** 2330 * set one line headers breaking mode 2331 */ 2332 void ASFormatter::setBreakOneLineHeadersMode(bool state) 2333 { 2334 shouldBreakOneLineHeaders = state; 2335 } 2336 2337 /** 2338 * set option to break/not break lines consisting of multiple statements. 2339 * 2340 * @param state true = break, false = don't break. 2341 */ 2342 void ASFormatter::setBreakOneLineStatementsMode(bool state) 2343 { 2344 shouldBreakOneLineStatements = state; 2345 } 2346 2347 void ASFormatter::setCloseTemplatesMode(bool state) 2348 { 2349 shouldCloseTemplates = state; 2350 } 2351 2352 /** 2353 * set option to convert tabs to spaces. 2354 * 2355 * @param state true = convert, false = don't convert. 2356 */ 2357 void ASFormatter::setTabSpaceConversionMode(bool state) 2358 { 2359 shouldConvertTabs = state; 2360 } 2361 2362 /** 2363 * set option to indent comments in column 1. 2364 * 2365 * @param state true = indent, false = don't indent. 2366 */ 2367 void ASFormatter::setIndentCol1CommentsMode(bool state) 2368 { 2369 shouldIndentCol1Comments = state; 2370 } 2371 2372 /** 2373 * set option to force all line ends to a particular style. 2374 * 2375 * @param fmt format enum value 2376 */ 2377 void ASFormatter::setLineEndFormat(LineEndFormat fmt) 2378 { 2379 lineEnd = fmt; 2380 } 2381 2382 /** 2383 * set option to break unrelated blocks of code with empty lines. 2384 * 2385 * @param state true = convert, false = don't convert. 2386 */ 2387 void ASFormatter::setBreakBlocksMode(bool state) 2388 { 2389 shouldBreakBlocks = state; 2390 } 2391 2392 /** 2393 * set option to break closing header blocks of code (such as 'else', 'catch', ...) with empty lines. 2394 * 2395 * @param state true = convert, false = don't convert. 2396 */ 2397 void ASFormatter::setBreakClosingHeaderBlocksMode(bool state) 2398 { 2399 shouldBreakClosingHeaderBlocks = state; 2400 } 2401 2402 /** 2403 * set option to delete empty lines. 2404 * 2405 * @param state true = delete, false = don't delete. 2406 */ 2407 void ASFormatter::setDeleteEmptyLinesMode(bool state) 2408 { 2409 shouldDeleteEmptyLines = state; 2410 } 2411 2412 void ASFormatter::setBreakReturnType(bool state) 2413 { 2414 shouldBreakReturnType = state; 2415 } 2416 2417 void ASFormatter::setBreakReturnTypeDecl(bool state) 2418 { 2419 shouldBreakReturnTypeDecl = state; 2420 } 2421 2422 void ASFormatter::setAttachReturnType(bool state) 2423 { 2424 shouldAttachReturnType = state; 2425 } 2426 2427 void ASFormatter::setAttachReturnTypeDecl(bool state) 2428 { 2429 shouldAttachReturnTypeDecl = state; 2430 } 2431 2432 /** 2433 * set the pointer alignment. 2434 * 2435 * @param alignment the pointer alignment. 2436 */ 2437 void ASFormatter::setPointerAlignment(PointerAlign alignment) 2438 { 2439 pointerAlignment = alignment; 2440 } 2441 2442 void ASFormatter::setReferenceAlignment(ReferenceAlign alignment) 2443 { 2444 referenceAlignment = alignment; 2445 } 2446 2447 /** 2448 * jump over several characters. 2449 * 2450 * @param i the number of characters to jump over. 2451 */ 2452 void ASFormatter::goForward(int i) 2453 { 2454 while (--i >= 0) 2455 getNextChar(); 2456 } 2457 2458 /** 2459 * peek at the next unread character. 2460 * 2461 * @return the next unread character. 2462 */ 2463 char ASFormatter::peekNextChar() const 2464 { 2465 char ch = ' '; 2466 size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1); 2467 2468 if (peekNum == string::npos) 2469 return ch; 2470 2471 ch = currentLine[peekNum]; 2472 2473 return ch; 2474 } 2475 2476 /** 2477 * check if current placement is before a comment 2478 * 2479 * @return is before a comment. 2480 */ 2481 bool ASFormatter::isBeforeComment() const 2482 { 2483 bool foundComment = false; 2484 size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1); 2485 2486 if (peekNum == string::npos) 2487 return foundComment; 2488 2489 foundComment = (currentLine.compare(peekNum, 2, "/*") == 0); 2490 2491 return foundComment; 2492 } 2493 2494 /** 2495 * check if current placement is before a comment or line-comment 2496 * 2497 * @return is before a comment or line-comment. 2498 */ 2499 bool ASFormatter::isBeforeAnyComment() const 2500 { 2501 bool foundComment = false; 2502 size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1); 2503 2504 if (peekNum == string::npos) 2505 return foundComment; 2506 2507 foundComment = (currentLine.compare(peekNum, 2, "/*") == 0 2508 || currentLine.compare(peekNum, 2, "//") == 0); 2509 2510 return foundComment; 2511 } 2512 2513 /** 2514 * check if current placement is before a comment or line-comment 2515 * if a block comment it must be at the end of the line 2516 * 2517 * @return is before a comment or line-comment. 2518 */ 2519 bool ASFormatter::isBeforeAnyLineEndComment(int startPos) const 2520 { 2521 bool foundLineEndComment = false; 2522 size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1); 2523 2524 if (peekNum != string::npos) 2525 { 2526 if (currentLine.compare(peekNum, 2, "//") == 0) 2527 foundLineEndComment = true; 2528 else if (currentLine.compare(peekNum, 2, "/*") == 0) 2529 { 2530 // comment must be closed on this line with nothing after it 2531 size_t endNum = currentLine.find("*/", peekNum + 2); 2532 if (endNum != string::npos) 2533 { 2534 size_t nextChar = currentLine.find_first_not_of(" \t", endNum + 2); 2535 if (nextChar == string::npos) 2536 foundLineEndComment = true; 2537 } 2538 } 2539 } 2540 return foundLineEndComment; 2541 } 2542 2543 /** 2544 * check if current placement is before a comment followed by a line-comment 2545 * 2546 * @return is before a multiple line-end comment. 2547 */ 2548 bool ASFormatter::isBeforeMultipleLineEndComments(int startPos) const 2549 { 2550 bool foundMultipleLineEndComment = false; 2551 size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1); 2552 2553 if (peekNum != string::npos) 2554 { 2555 if (currentLine.compare(peekNum, 2, "/*") == 0) 2556 { 2557 // comment must be closed on this line with nothing after it 2558 size_t endNum = currentLine.find("*/", peekNum + 2); 2559 if (endNum != string::npos) 2560 { 2561 size_t nextChar = currentLine.find_first_not_of(" \t", endNum + 2); 2562 if (nextChar != string::npos 2563 && currentLine.compare(nextChar, 2, "//") == 0) 2564 foundMultipleLineEndComment = true; 2565 } 2566 } 2567 } 2568 return foundMultipleLineEndComment; 2569 } 2570 2571 /** 2572 * get the next character, increasing the current placement in the process. 2573 * the new character is inserted into the variable currentChar. 2574 * 2575 * @return whether succeeded to receive the new character. 2576 */ 2577 bool ASFormatter::getNextChar() 2578 { 2579 isInLineBreak = false; 2580 previousChar = currentChar; 2581 2582 if (!isWhiteSpace(currentChar)) 2583 { 2584 previousNonWSChar = currentChar; 2585 if (!isInComment && !isInLineComment && !isInQuote 2586 && !isImmediatelyPostComment 2587 && !isImmediatelyPostLineComment 2588 && !isInPreprocessor 2589 && !isSequenceReached("/*") 2590 && !isSequenceReached("//")) 2591 previousCommandChar = currentChar; 2592 } 2593 2594 if (charNum + 1 < (int) currentLine.length() 2595 && (!isWhiteSpace(peekNextChar()) || isInComment || isInLineComment)) 2596 { 2597 currentChar = currentLine[++charNum]; 2598 2599 if (currentChar == '\t' && shouldConvertTabs) 2600 convertTabToSpaces(); 2601 2602 return true; 2603 } 2604 2605 // end of line has been reached 2606 return getNextLine(); 2607 } 2608 2609 /** 2610 * get the next line of input, increasing the current placement in the process. 2611 * 2612 * @param emptyLineWasDeleted an empty line was deleted. 2613 * @return whether succeeded in reading the next line. 2614 */ 2615 bool ASFormatter::getNextLine(bool emptyLineWasDeleted /*false*/) 2616 { 2617 if (!sourceIterator->hasMoreLines()) 2618 { 2619 endOfCodeReached = true; 2620 return false; 2621 } 2622 if (appendOpeningBrace) 2623 currentLine = "{"; // append brace that was removed from the previous line 2624 else 2625 { 2626 currentLine = sourceIterator->nextLine(emptyLineWasDeleted); 2627 assert(computeChecksumIn(currentLine)); 2628 } 2629 // reset variables for new line 2630 inLineNumber++; 2631 if (endOfAsmReached) 2632 endOfAsmReached = isInAsmBlock = isInAsm = false; 2633 shouldKeepLineUnbroken = false; 2634 isInCommentStartLine = false; 2635 isInCase = false; 2636 isInAsmOneLine = false; 2637 isHeaderInMultiStatementLine = false; 2638 isInQuoteContinuation = isInVerbatimQuote || haveLineContinuationChar; 2639 haveLineContinuationChar = false; 2640 isImmediatelyPostEmptyLine = lineIsEmpty; 2641 previousChar = ' '; 2642 2643 if (currentLine.length() == 0) 2644 currentLine = string(" "); // a null is inserted if this is not done 2645 2646 if (methodBreakLineNum > 0) 2647 --methodBreakLineNum; 2648 if (methodAttachLineNum > 0) 2649 --methodAttachLineNum; 2650 2651 // unless reading in the first line of the file, break a new line. 2652 if (!isVirgin) 2653 isInLineBreak = true; 2654 else 2655 isVirgin = false; 2656 2657 if (isImmediatelyPostNonInStmt) 2658 { 2659 isCharImmediatelyPostNonInStmt = true; 2660 isImmediatelyPostNonInStmt = false; 2661 } 2662 2663 // check if is in preprocessor before line trimming 2664 // a blank line after a \ will remove the flag 2665 isImmediatelyPostPreprocessor = isInPreprocessor; 2666 if (!isInComment 2667 && (previousNonWSChar != '\\' 2668 || isEmptyLine(currentLine))) 2669 isInPreprocessor = false; 2670 2671 if (passedSemicolon) 2672 isInExecSQL = false; 2673 initNewLine(); 2674 2675 currentChar = currentLine[charNum]; 2676 if (isInBraceRunIn && previousNonWSChar == '{' && !isInComment) 2677 isInLineBreak = false; 2678 isInBraceRunIn = false; 2679 2680 if (currentChar == '\t' && shouldConvertTabs) 2681 convertTabToSpaces(); 2682 2683 // check for an empty line inside a command brace. 2684 // if yes then read the next line (calls getNextLine recursively). 2685 // must be after initNewLine. 2686 if (shouldDeleteEmptyLines 2687 && lineIsEmpty 2688 && isBraceType((*braceTypeStack)[braceTypeStack->size() - 1], COMMAND_TYPE)) 2689 { 2690 if (!shouldBreakBlocks || previousNonWSChar == '{' || !commentAndHeaderFollows()) 2691 { 2692 isInPreprocessor = isImmediatelyPostPreprocessor; // restore 2693 lineIsEmpty = false; 2694 return getNextLine(true); 2695 } 2696 } 2697 return true; 2698 } 2699 2700 /** 2701 * jump over the leading white space in the current line, 2702 * IF the line does not begin a comment or is in a preprocessor definition. 2703 */ 2704 void ASFormatter::initNewLine() 2705 { 2706 size_t len = currentLine.length(); 2707 size_t tabSize = getTabLength(); 2708 charNum = 0; 2709 2710 // don't trim these 2711 if (isInQuoteContinuation 2712 || (isInPreprocessor && !getPreprocDefineIndent())) 2713 return; 2714 2715 // SQL continuation lines must be adjusted so the leading spaces 2716 // is equivalent to the opening EXEC SQL 2717 if (isInExecSQL) 2718 { 2719 // replace leading tabs with spaces 2720 // so that continuation indent will be spaces 2721 size_t tabCount_ = 0; 2722 size_t i; 2723 for (i = 0; i < currentLine.length(); i++) 2724 { 2725 if (!isWhiteSpace(currentLine[i])) // stop at first text 2726 break; 2727 if (currentLine[i] == '\t') 2728 { 2729 size_t numSpaces = tabSize - ((tabCount_ + i) % tabSize); 2730 currentLine.replace(i, 1, numSpaces, ' '); 2731 tabCount_++; 2732 i += tabSize - 1; 2733 } 2734 } 2735 // this will correct the format if EXEC SQL is not a hanging indent 2736 trimContinuationLine(); 2737 return; 2738 } 2739 2740 // comment continuation lines must be adjusted so the leading spaces 2741 // is equivalent to the opening comment 2742 if (isInComment) 2743 { 2744 if (noTrimCommentContinuation) 2745 leadingSpaces = tabIncrementIn = 0; 2746 trimContinuationLine(); 2747 return; 2748 } 2749 2750 // compute leading spaces 2751 isImmediatelyPostCommentOnly = lineIsLineCommentOnly || lineEndsInCommentOnly; 2752 lineIsCommentOnly = false; 2753 lineIsLineCommentOnly = false; 2754 lineEndsInCommentOnly = false; 2755 doesLineStartComment = false; 2756 currentLineBeginsWithBrace = false; 2757 lineIsEmpty = false; 2758 currentLineFirstBraceNum = string::npos; 2759 tabIncrementIn = 0; 2760 2761 // bypass whitespace at the start of a line 2762 // preprocessor tabs are replaced later in the program 2763 for (charNum = 0; isWhiteSpace(currentLine[charNum]) && charNum + 1 < (int) len; charNum++) 2764 { 2765 if (currentLine[charNum] == '\t' && !isInPreprocessor) 2766 tabIncrementIn += tabSize - 1 - ((tabIncrementIn + charNum) % tabSize); 2767 } 2768 leadingSpaces = charNum + tabIncrementIn; 2769 2770 if (isSequenceReached("/*")) 2771 { 2772 doesLineStartComment = true; 2773 if ((int) currentLine.length() > charNum + 2 2774 && currentLine.find("*/", charNum + 2) != string::npos) 2775 lineIsCommentOnly = true; 2776 } 2777 else if (isSequenceReached("//")) 2778 { 2779 lineIsLineCommentOnly = true; 2780 } 2781 else if (isSequenceReached("{")) 2782 { 2783 currentLineBeginsWithBrace = true; 2784 currentLineFirstBraceNum = charNum; 2785 size_t firstText = currentLine.find_first_not_of(" \t", charNum + 1); 2786 if (firstText != string::npos) 2787 { 2788 if (currentLine.compare(firstText, 2, "//") == 0) 2789 lineIsLineCommentOnly = true; 2790 else if (currentLine.compare(firstText, 2, "/*") == 0 2791 || isExecSQL(currentLine, firstText)) 2792 { 2793 // get the extra adjustment 2794 size_t j; 2795 for (j = charNum + 1; j < firstText && isWhiteSpace(currentLine[j]); j++) 2796 { 2797 if (currentLine[j] == '\t') 2798 tabIncrementIn += tabSize - 1 - ((tabIncrementIn + j) % tabSize); 2799 } 2800 leadingSpaces = j + tabIncrementIn; 2801 if (currentLine.compare(firstText, 2, "/*") == 0) 2802 doesLineStartComment = true; 2803 } 2804 } 2805 } 2806 else if (isWhiteSpace(currentLine[charNum]) && !(charNum + 1 < (int) currentLine.length())) 2807 { 2808 lineIsEmpty = true; 2809 } 2810 2811 // do not trim indented preprocessor define (except for comment continuation lines) 2812 if (isInPreprocessor) 2813 { 2814 if (!doesLineStartComment) 2815 leadingSpaces = 0; 2816 charNum = 0; 2817 } 2818 } 2819 2820 /** 2821 * Append a character to the current formatted line. 2822 * The formattedLine split points are updated. 2823 * 2824 * @param ch the character to append. 2825 * @param canBreakLine if true, a registered line-break 2826 */ 2827 void ASFormatter::appendChar(char ch, bool canBreakLine) 2828 { 2829 if (canBreakLine && isInLineBreak) 2830 breakLine(); 2831 2832 formattedLine.append(1, ch); 2833 isImmediatelyPostCommentOnly = false; 2834 if (maxCodeLength != string::npos) 2835 { 2836 // These compares reduce the frequency of function calls. 2837 if (isOkToSplitFormattedLine()) 2838 updateFormattedLineSplitPoints(ch); 2839 if (formattedLine.length() > maxCodeLength) 2840 testForTimeToSplitFormattedLine(); 2841 } 2842 } 2843 2844 /** 2845 * Append a string sequence to the current formatted line. 2846 * The formattedLine split points are NOT updated. 2847 * But the formattedLine is checked for time to split. 2848 * 2849 * @param sequence the sequence to append. 2850 * @param canBreakLine if true, a registered line-break 2851 */ 2852 void ASFormatter::appendSequence(const string& sequence, bool canBreakLine) 2853 { 2854 if (canBreakLine && isInLineBreak) 2855 breakLine(); 2856 formattedLine.append(sequence); 2857 if (formattedLine.length() > maxCodeLength) 2858 testForTimeToSplitFormattedLine(); 2859 } 2860 2861 /** 2862 * Append an operator sequence to the current formatted line. 2863 * The formattedLine split points are updated. 2864 * 2865 * @param sequence the sequence to append. 2866 * @param canBreakLine if true, a registered line-break 2867 */ 2868 void ASFormatter::appendOperator(const string& sequence, bool canBreakLine) 2869 { 2870 if (canBreakLine && isInLineBreak) 2871 breakLine(); 2872 formattedLine.append(sequence); 2873 if (maxCodeLength != string::npos) 2874 { 2875 // These compares reduce the frequency of function calls. 2876 if (isOkToSplitFormattedLine()) 2877 updateFormattedLineSplitPointsOperator(sequence); 2878 if (formattedLine.length() > maxCodeLength) 2879 testForTimeToSplitFormattedLine(); 2880 } 2881 } 2882 2883 /** 2884 * append a space to the current formattedline, UNLESS the 2885 * last character is already a white-space character. 2886 */ 2887 void ASFormatter::appendSpacePad() 2888 { 2889 int len = formattedLine.length(); 2890 if (len > 0 && !isWhiteSpace(formattedLine[len - 1])) 2891 { 2892 formattedLine.append(1, ' '); 2893 spacePadNum++; 2894 if (maxCodeLength != string::npos) 2895 { 2896 // These compares reduce the frequency of function calls. 2897 if (isOkToSplitFormattedLine()) 2898 updateFormattedLineSplitPoints(' '); 2899 if (formattedLine.length() > maxCodeLength) 2900 testForTimeToSplitFormattedLine(); 2901 } 2902 } 2903 } 2904 2905 /** 2906 * append a space to the current formattedline, UNLESS the 2907 * next character is already a white-space character. 2908 */ 2909 void ASFormatter::appendSpaceAfter() 2910 { 2911 int len = currentLine.length(); 2912 if (charNum + 1 < len && !isWhiteSpace(currentLine[charNum + 1])) 2913 { 2914 formattedLine.append(1, ' '); 2915 spacePadNum++; 2916 if (maxCodeLength != string::npos) 2917 { 2918 // These compares reduce the frequency of function calls. 2919 if (isOkToSplitFormattedLine()) 2920 updateFormattedLineSplitPoints(' '); 2921 if (formattedLine.length() > maxCodeLength) 2922 testForTimeToSplitFormattedLine(); 2923 } 2924 } 2925 } 2926 2927 /** 2928 * register a line break for the formatted line. 2929 */ 2930 void ASFormatter::breakLine(bool isSplitLine /*false*/) 2931 { 2932 isLineReady = true; 2933 isInLineBreak = false; 2934 spacePadNum = nextLineSpacePadNum; 2935 nextLineSpacePadNum = 0; 2936 readyFormattedLine = formattedLine; 2937 formattedLine.erase(); 2938 // queue an empty line prepend request if one exists 2939 prependEmptyLine = isPrependPostBlockEmptyLineRequested; 2940 2941 if (!isSplitLine) 2942 { 2943 formattedLineCommentNum = string::npos; 2944 clearFormattedLineSplitPoints(); 2945 2946 if (isAppendPostBlockEmptyLineRequested) 2947 { 2948 isAppendPostBlockEmptyLineRequested = false; 2949 isPrependPostBlockEmptyLineRequested = true; 2950 } 2951 else 2952 isPrependPostBlockEmptyLineRequested = false; 2953 } 2954 } 2955 2956 /** 2957 * check if the currently reached open-brace (i.e. '{') 2958 * opens a: 2959 * - a definition type block (such as a class or namespace), 2960 * - a command block (such as a method block) 2961 * - a static array 2962 * this method takes for granted that the current character 2963 * is an opening brace. 2964 * 2965 * @return the type of the opened block. 2966 */ 2967 BraceType ASFormatter::getBraceType() 2968 { 2969 assert(currentChar == '{'); 2970 2971 BraceType returnVal = NULL_TYPE; 2972 2973 if ((previousNonWSChar == '=' 2974 || isBraceType(braceTypeStack->back(), ARRAY_TYPE)) 2975 && previousCommandChar != ')' 2976 && !isNonParenHeader) 2977 returnVal = ARRAY_TYPE; 2978 else if (foundPreDefinitionHeader && previousCommandChar != ')') 2979 { 2980 returnVal = DEFINITION_TYPE; 2981 if (foundNamespaceHeader) 2982 returnVal = (BraceType)(returnVal | NAMESPACE_TYPE); 2983 else if (foundClassHeader) 2984 returnVal = (BraceType)(returnVal | CLASS_TYPE); 2985 else if (foundStructHeader) 2986 returnVal = (BraceType)(returnVal | STRUCT_TYPE); 2987 else if (foundInterfaceHeader) 2988 returnVal = (BraceType)(returnVal | INTERFACE_TYPE); 2989 } 2990 else if (isInEnum) 2991 { 2992 returnVal = (BraceType)(ARRAY_TYPE | ENUM_TYPE); 2993 } 2994 else 2995 { 2996 bool isCommandType = (foundPreCommandHeader 2997 || foundPreCommandMacro 2998 || (currentHeader != nullptr && isNonParenHeader) 2999 || (previousCommandChar == ')') 3000 || (previousCommandChar == ':' && !foundQuestionMark) 3001 || (previousCommandChar == ';') 3002 || ((previousCommandChar == '{' || previousCommandChar == '}') 3003 && isPreviousBraceBlockRelated) 3004 || (isInClassInitializer 3005 && ((!isLegalNameChar(previousNonWSChar) && previousNonWSChar != '(') 3006 || foundPreCommandHeader)) 3007 || foundTrailingReturnType 3008 || isInObjCMethodDefinition 3009 || isInObjCInterface 3010 || isJavaStaticConstructor 3011 || isSharpDelegate); 3012 3013 // C# methods containing 'get', 'set', 'add', and 'remove' do NOT end with parens 3014 if (!isCommandType && isSharpStyle() && isNextWordSharpNonParenHeader(charNum + 1)) 3015 { 3016 isCommandType = true; 3017 isSharpAccessor = true; 3018 } 3019 3020 if (isInExternC) 3021 returnVal = (isCommandType ? COMMAND_TYPE : EXTERN_TYPE); 3022 else 3023 returnVal = (isCommandType ? COMMAND_TYPE : ARRAY_TYPE); 3024 } 3025 3026 int foundOneLineBlock = isOneLineBlockReached(currentLine, charNum); 3027 3028 if (foundOneLineBlock == 2 && returnVal == COMMAND_TYPE) 3029 returnVal = ARRAY_TYPE; 3030 3031 if (foundOneLineBlock > 0) 3032 { 3033 returnVal = (BraceType) (returnVal | SINGLE_LINE_TYPE); 3034 if (breakCurrentOneLineBlock) 3035 returnVal = (BraceType) (returnVal | BREAK_BLOCK_TYPE); 3036 if (foundOneLineBlock == 3) 3037 returnVal = (BraceType)(returnVal | EMPTY_BLOCK_TYPE); 3038 } 3039 3040 if (isBraceType(returnVal, ARRAY_TYPE)) 3041 { 3042 if (isNonInStatementArrayBrace()) 3043 { 3044 returnVal = (BraceType)(returnVal | ARRAY_NIS_TYPE); 3045 isNonInStatementArray = true; 3046 isImmediatelyPostNonInStmt = false; // in case of "},{" 3047 nonInStatementBrace = formattedLine.length() - 1; 3048 } 3049 if (isUniformInitializerBrace()) 3050 returnVal = (BraceType)(returnVal | INIT_TYPE); 3051 } 3052 3053 return returnVal; 3054 } 3055 3056 bool ASFormatter::isNumericVariable(string word) const 3057 { 3058 if (word == "bool" 3059 || word == "int" 3060 || word == "void" 3061 || word == "char" 3062 || word == "long" 3063 || word == "short" 3064 || word == "double" 3065 || word == "float" 3066 || (word.length() >= 4 // check end of word for _t 3067 && word.compare(word.length() - 2, 2, "_t") == 0) 3068 // removed release 3.1 3069 // || word == "Int32" 3070 // || word == "UInt32" 3071 // || word == "Int64" 3072 // || word == "UInt64" 3073 || word == "BOOL" 3074 || word == "DWORD" 3075 || word == "HWND" 3076 || word == "INT" 3077 || word == "LPSTR" 3078 || word == "VOID" 3079 || word == "LPVOID" 3080 || word == "wxFontEncoding" 3081 ) 3082 return true; 3083 return false; 3084 } 3085 3086 /** 3087 * check if a colon is a class initializer separator 3088 * 3089 * @return whether it is a class initializer separator 3090 */ 3091 bool ASFormatter::isClassInitializer() const 3092 { 3093 assert(currentChar == ':'); 3094 assert(previousChar != ':' && peekNextChar() != ':'); // not part of '::' 3095 3096 // this should be similar to ASBeautifier::parseCurrentLine() 3097 bool foundClassInitializer = false; 3098 3099 if (foundQuestionMark) 3100 { 3101 // do nothing special 3102 } 3103 else if (parenStack->back() > 0) 3104 { 3105 // found a 'for' loop or an objective-C statement 3106 // so do nothing special 3107 } 3108 else if (isInEnum) 3109 { 3110 // found an enum with a base-type 3111 } 3112 else if (isCStyle() 3113 && !isInCase 3114 && (previousCommandChar == ')' || foundPreCommandHeader)) 3115 { 3116 // found a 'class' c'tor initializer 3117 foundClassInitializer = true; 3118 } 3119 return foundClassInitializer; 3120 } 3121 3122 /** 3123 * check if a line is empty 3124 * 3125 * @return whether line is empty 3126 */ 3127 bool ASFormatter::isEmptyLine(const string& line) const 3128 { 3129 return line.find_first_not_of(" \t") == string::npos; 3130 } 3131 3132 /** 3133 * Check if the following text is "C" as in extern "C". 3134 * 3135 * @return whether the statement is extern "C" 3136 */ 3137 bool ASFormatter::isExternC() const 3138 { 3139 // charNum should be at 'extern' 3140 assert(!isWhiteSpace(currentLine[charNum])); 3141 size_t startQuote = currentLine.find_first_of(" \t\"", charNum); 3142 if (startQuote == string::npos) 3143 return false; 3144 startQuote = currentLine.find_first_not_of(" \t", startQuote); 3145 if (startQuote == string::npos) 3146 return false; 3147 if (currentLine.compare(startQuote, 3, "\"C\"") != 0) 3148 return false; 3149 return true; 3150 } 3151 3152 /** 3153 * Check if the currently reached '*', '&' or '^' character is 3154 * a pointer-or-reference symbol, or another operator. 3155 * A pointer dereference (*) or an "address of" character (&) 3156 * counts as a pointer or reference because it is not an 3157 * arithmetic operator. 3158 * 3159 * @return whether current character is a reference-or-pointer 3160 */ 3161 bool ASFormatter::isPointerOrReference() const 3162 { 3163 assert(currentChar == '*' || currentChar == '&' || currentChar == '^'); 3164 3165 if (isJavaStyle()) 3166 return false; 3167 3168 if (isCharImmediatelyPostOperator) 3169 return false; 3170 3171 // get the last legal word (may be a number) 3172 string lastWord = getPreviousWord(currentLine, charNum); 3173 if (lastWord.empty()) 3174 lastWord = " "; 3175 3176 // check for preceding or following numeric values 3177 string nextText = peekNextText(currentLine.substr(charNum + 1)); 3178 if (nextText.length() == 0) 3179 nextText = " "; 3180 if (isDigit(lastWord[0]) 3181 || isDigit(nextText[0]) 3182 || nextText[0] == '!' 3183 || nextText[0] == '~') 3184 return false; 3185 3186 // check for multiply then a dereference (a * *b) 3187 char nextChar = peekNextChar(); 3188 if (currentChar == '*' 3189 && nextChar == '*' 3190 && !isPointerToPointer(currentLine, charNum)) 3191 return false; 3192 3193 if ((foundCastOperator && nextChar == '>') 3194 || isPointerOrReferenceVariable(lastWord)) 3195 return true; 3196 3197 if (isInClassInitializer 3198 && previousNonWSChar != '(' 3199 && previousNonWSChar != '{' 3200 && previousCommandChar != ',' 3201 && nextChar != ')' 3202 && nextChar != '}') 3203 return false; 3204 3205 //check for rvalue reference 3206 if (currentChar == '&' && nextChar == '&') 3207 { 3208 if (lastWord == AS_AUTO) 3209 return true; 3210 if (previousNonWSChar == '>') 3211 return true; 3212 string followingText; 3213 if ((int) currentLine.length() > charNum + 2) 3214 followingText = peekNextText(currentLine.substr(charNum + 2)); 3215 if (followingText.length() > 0 && followingText[0] == ')') 3216 return true; 3217 if (currentHeader != nullptr || isInPotentialCalculation) 3218 return false; 3219 if (parenStack->back() > 0 && isBraceType(braceTypeStack->back(), COMMAND_TYPE)) 3220 return false; 3221 return true; 3222 } 3223 if (nextChar == '*' 3224 || previousNonWSChar == '=' 3225 || previousNonWSChar == '(' 3226 || previousNonWSChar == '[' 3227 || isCharImmediatelyPostReturn 3228 || isInTemplate 3229 || isCharImmediatelyPostTemplate 3230 || currentHeader == &AS_CATCH 3231 || currentHeader == &AS_FOREACH 3232 || currentHeader == &AS_QFOREACH) 3233 return true; 3234 3235 if (isBraceType(braceTypeStack->back(), ARRAY_TYPE) 3236 && isLegalNameChar(lastWord[0]) 3237 && isLegalNameChar(nextChar) 3238 && previousNonWSChar != ')') 3239 { 3240 if (isArrayOperator()) 3241 return false; 3242 } 3243 3244 // checks on operators in parens 3245 if (parenStack->back() > 0 3246 && isLegalNameChar(lastWord[0]) 3247 && isLegalNameChar(nextChar)) 3248 { 3249 // if followed by an assignment it is a pointer or reference 3250 // if followed by semicolon it is a pointer or reference in range-based for 3251 const string* followingOperator = getFollowingOperator(); 3252 if (followingOperator != nullptr 3253 && followingOperator != &AS_MULT 3254 && followingOperator != &AS_BIT_AND) 3255 { 3256 if (followingOperator == &AS_ASSIGN || followingOperator == &AS_COLON) 3257 return true; 3258 return false; 3259 } 3260 3261 if (isBraceType(braceTypeStack->back(), COMMAND_TYPE) 3262 || squareBracketCount > 0) 3263 return false; 3264 return true; 3265 } 3266 3267 // checks on operators in parens with following '(' 3268 if (parenStack->back() > 0 3269 && nextChar == '(' 3270 && previousNonWSChar != ',' 3271 && previousNonWSChar != '(' 3272 && previousNonWSChar != '!' 3273 && previousNonWSChar != '&' 3274 && previousNonWSChar != '*' 3275 && previousNonWSChar != '|') 3276 return false; 3277 3278 if (nextChar == '-' 3279 || nextChar == '+') 3280 { 3281 size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1); 3282 if (nextNum != string::npos) 3283 { 3284 if (currentLine.compare(nextNum, 2, "++") != 0 3285 && currentLine.compare(nextNum, 2, "--") != 0) 3286 return false; 3287 } 3288 } 3289 3290 bool isPR = (!isInPotentialCalculation 3291 || (!isLegalNameChar(previousNonWSChar) 3292 && !(previousNonWSChar == ')' && nextChar == '(') 3293 && !(previousNonWSChar == ')' && currentChar == '*' && !isImmediatelyPostCast()) 3294 && previousNonWSChar != ']') 3295 || (!isWhiteSpace(nextChar) 3296 && nextChar != '-' 3297 && nextChar != '(' 3298 && nextChar != '[' 3299 && !isLegalNameChar(nextChar)) 3300 ); 3301 3302 return isPR; 3303 } 3304 3305 /** 3306 * Check if the currently reached '*' or '&' character is 3307 * a dereferenced pointer or "address of" symbol. 3308 * NOTE: this MUST be a pointer or reference as determined by 3309 * the function isPointerOrReference(). 3310 * 3311 * @return whether current character is a dereference or address of 3312 */ 3313 bool ASFormatter::isDereferenceOrAddressOf() const 3314 { 3315 assert(currentChar == '*' || currentChar == '&' || currentChar == '^'); 3316 3317 if (isCharImmediatelyPostTemplate) 3318 return false; 3319 3320 if (previousNonWSChar == '=' 3321 || previousNonWSChar == ',' 3322 || previousNonWSChar == '.' 3323 || previousNonWSChar == '{' 3324 || previousNonWSChar == '>' 3325 || previousNonWSChar == '<' 3326 || previousNonWSChar == '?' 3327 || isCharImmediatelyPostLineComment 3328 || isCharImmediatelyPostComment 3329 || isCharImmediatelyPostReturn) 3330 return true; 3331 3332 char nextChar = peekNextChar(); 3333 if (currentChar == '*' && nextChar == '*') 3334 { 3335 if (previousNonWSChar == '(') 3336 return true; 3337 if ((int) currentLine.length() < charNum + 2) 3338 return true; 3339 return false; 3340 } 3341 if (currentChar == '&' && nextChar == '&') 3342 { 3343 if (previousNonWSChar == '(' || isInTemplate) 3344 return true; 3345 if ((int) currentLine.length() < charNum + 2) 3346 return true; 3347 return false; 3348 } 3349 3350 // check first char on the line 3351 if (charNum == (int) currentLine.find_first_not_of(" \t") 3352 && (isBraceType(braceTypeStack->back(), COMMAND_TYPE) 3353 || parenStack->back() != 0)) 3354 return true; 3355 3356 string nextText = peekNextText(currentLine.substr(charNum + 1)); 3357 if (nextText.length() > 0) 3358 { 3359 if (nextText[0] == ')' || nextText[0] == '>' 3360 || nextText[0] == ',' || nextText[0] == '=') 3361 return false; 3362 if (nextText[0] == ';') 3363 return true; 3364 } 3365 3366 // check for reference to a pointer *& 3367 if ((currentChar == '*' && nextChar == '&') 3368 || (previousNonWSChar == '*' && currentChar == '&')) 3369 return false; 3370 3371 if (!isBraceType(braceTypeStack->back(), COMMAND_TYPE) 3372 && parenStack->back() == 0) 3373 return false; 3374 3375 string lastWord = getPreviousWord(currentLine, charNum); 3376 if (lastWord == "else" || lastWord == "delete") 3377 return true; 3378 3379 if (isPointerOrReferenceVariable(lastWord)) 3380 return false; 3381 3382 bool isDA = (!(isLegalNameChar(previousNonWSChar) || previousNonWSChar == '>') 3383 || (nextText.length() > 0 && !isLegalNameChar(nextText[0]) && nextText[0] != '/') 3384 || (ispunct((unsigned char)previousNonWSChar) && previousNonWSChar != '.') 3385 || isCharImmediatelyPostReturn); 3386 3387 return isDA; 3388 } 3389 3390 /** 3391 * Check if the currently reached '*' or '&' character is 3392 * centered with one space on each side. 3393 * Only spaces are checked, not tabs. 3394 * If true then a space will be deleted on the output. 3395 * 3396 * @return whether current character is centered. 3397 */ 3398 bool ASFormatter::isPointerOrReferenceCentered() const 3399 { 3400 assert(currentChar == '*' || currentChar == '&' || currentChar == '^'); 3401 3402 int prNum = charNum; 3403 int lineLength = (int) currentLine.length(); 3404 3405 // check for end of line 3406 if (peekNextChar() == ' ') 3407 return false; 3408 3409 // check space before 3410 if (prNum < 1 3411 || currentLine[prNum - 1] != ' ') 3412 return false; 3413 3414 // check no space before that 3415 if (prNum < 2 3416 || currentLine[prNum - 2] == ' ') 3417 return false; 3418 3419 // check for ** or && 3420 if (prNum + 1 < lineLength 3421 && (currentLine[prNum + 1] == '*' || currentLine[prNum + 1] == '&')) 3422 prNum++; 3423 3424 // check space after 3425 if (prNum + 1 <= lineLength 3426 && currentLine[prNum + 1] != ' ') 3427 return false; 3428 3429 // check no space after that 3430 if (prNum + 2 < lineLength 3431 && currentLine[prNum + 2] == ' ') 3432 return false; 3433 3434 return true; 3435 } 3436 3437 /** 3438 * Check if a word is a pointer or reference variable type. 3439 * 3440 * @return whether word is a pointer or reference variable. 3441 */ 3442 bool ASFormatter::isPointerOrReferenceVariable(const string& word) const 3443 { 3444 return (word == "char" 3445 || word == "int" 3446 || word == "void" 3447 || (word.length() >= 6 // check end of word for _t 3448 && word.compare(word.length() - 2, 2, "_t") == 0) 3449 || word == "INT" 3450 || word == "VOID"); 3451 } 3452 3453 /** 3454 * Check if * * is a pointer to a pointer or a multiply then a dereference. 3455 * 3456 * @return true if a pointer *. 3457 */ 3458 bool ASFormatter::isPointerToPointer(const string& line, int currPos) const 3459 { 3460 assert(line[currPos] == '*' && peekNextChar() == '*'); 3461 if ((int) line.length() > currPos + 1 && line[currPos + 1] == '*') 3462 return true; 3463 size_t nextText = line.find_first_not_of(" \t", currPos + 1); 3464 if (nextText == string::npos || line[nextText] != '*') 3465 return false; 3466 size_t nextText2 = line.find_first_not_of(" \t", nextText + 1); 3467 if (nextText == string::npos) 3468 return false; 3469 if (line[nextText2] == ')' || line[nextText2] == '*') 3470 return true; 3471 return false; 3472 } 3473 3474 /** 3475 * check if the currently reached '+' or '-' character is a unary operator 3476 * this method takes for granted that the current character 3477 * is a '+' or '-'. 3478 * 3479 * @return whether the current '+' or '-' is a unary operator. 3480 */ 3481 bool ASFormatter::isUnaryOperator() const 3482 { 3483 assert(currentChar == '+' || currentChar == '-'); 3484 3485 // does a digit follow a c-style cast 3486 if (previousCommandChar == ')') 3487 { 3488 if (!isdigit(peekNextChar())) 3489 return false; 3490 size_t end = currentLine.rfind(')', charNum); 3491 if (end == string::npos) 3492 return false; 3493 size_t lastChar = currentLine.find_last_not_of(" \t", end - 1); 3494 if (lastChar == string::npos) 3495 return false; 3496 if (currentLine[lastChar] == '*') 3497 end = lastChar; 3498 string prevWord = getPreviousWord(currentLine, end); 3499 if (prevWord.empty()) 3500 return false; 3501 if (!isNumericVariable(prevWord)) 3502 return false; 3503 return true; 3504 } 3505 3506 return ((isCharImmediatelyPostReturn || !isLegalNameChar(previousCommandChar)) 3507 && previousCommandChar != '.' 3508 && previousCommandChar != '\"' 3509 && previousCommandChar != '\'' 3510 && previousCommandChar != ']'); 3511 } 3512 3513 /** 3514 * check if the currently reached comment is in a 'switch' statement 3515 * 3516 * @return whether the current '+' or '-' is in an exponent. 3517 */ 3518 bool ASFormatter::isInSwitchStatement() const 3519 { 3520 assert(isInLineComment || isInComment); 3521 if (!preBraceHeaderStack->empty()) 3522 for (size_t i = 1; i < preBraceHeaderStack->size(); i++) 3523 if (preBraceHeaderStack->at(i) == &AS_SWITCH) 3524 return true; 3525 return false; 3526 } 3527 3528 /** 3529 * check if the currently reached '+' or '-' character is 3530 * part of an exponent, i.e. 0.2E-5. 3531 * 3532 * @return whether the current '+' or '-' is in an exponent. 3533 */ 3534 bool ASFormatter::isInExponent() const 3535 { 3536 assert(currentChar == '+' || currentChar == '-'); 3537 3538 if (charNum >= 2) 3539 { 3540 char prevPrevFormattedChar = currentLine[charNum - 2]; 3541 char prevFormattedChar = currentLine[charNum - 1]; 3542 return ((prevFormattedChar == 'e' || prevFormattedChar == 'E') 3543 && (prevPrevFormattedChar == '.' || isDigit(prevPrevFormattedChar))); 3544 } 3545 return false; 3546 } 3547 3548 /** 3549 * check if an array brace should NOT have an in-statement indent 3550 * 3551 * @return the array is non in-statement 3552 */ 3553 bool ASFormatter::isNonInStatementArrayBrace() const 3554 { 3555 bool returnVal = false; 3556 char nextChar = peekNextChar(); 3557 // if this opening brace begins the line there will be no inStatement indent 3558 if (currentLineBeginsWithBrace 3559 && (size_t) charNum == currentLineFirstBraceNum 3560 && nextChar != '}') 3561 returnVal = true; 3562 // if an opening brace ends the line there will be no inStatement indent 3563 if (isWhiteSpace(nextChar) 3564 || isBeforeAnyLineEndComment(charNum) 3565 || nextChar == '{') 3566 returnVal = true; 3567 3568 // Java "new Type [] {...}" IS an inStatement indent 3569 if (isJavaStyle() && previousNonWSChar == ']') 3570 returnVal = false; 3571 3572 return returnVal; 3573 } 3574 3575 /** 3576 * check if a one-line block has been reached, 3577 * i.e. if the currently reached '{' character is closed 3578 * with a complimentary '}' elsewhere on the current line, 3579 *. 3580 * @return 0 = one-line block has not been reached. 3581 * 1 = one-line block has been reached. 3582 * 2 = one-line block has been reached and is followed by a comma. 3583 * 3 = one-line block has been reached and is an empty block. 3584 */ 3585 int ASFormatter::isOneLineBlockReached(const string& line, int startChar) const 3586 { 3587 assert(line[startChar] == '{'); 3588 3589 bool isInComment_ = false; 3590 bool isInQuote_ = false; 3591 bool hasText = false; 3592 int braceCount = 0; 3593 int lineLength = line.length(); 3594 char quoteChar_ = ' '; 3595 char ch = ' '; 3596 char prevCh = ' '; 3597 3598 for (int i = startChar; i < lineLength; ++i) 3599 { 3600 ch = line[i]; 3601 3602 if (isInComment_) 3603 { 3604 if (line.compare(i, 2, "*/") == 0) 3605 { 3606 isInComment_ = false; 3607 ++i; 3608 } 3609 continue; 3610 } 3611 3612 if (isInQuote_) 3613 { 3614 if (ch == '\\') 3615 ++i; 3616 else if (ch == quoteChar_) 3617 isInQuote_ = false; 3618 continue; 3619 } 3620 3621 if (ch == '"' 3622 || (ch == '\'' && !isDigitSeparator(line, i))) 3623 { 3624 isInQuote_ = true; 3625 quoteChar_ = ch; 3626 continue; 3627 } 3628 3629 if (line.compare(i, 2, "//") == 0) 3630 break; 3631 3632 if (line.compare(i, 2, "/*") == 0) 3633 { 3634 isInComment_ = true; 3635 ++i; 3636 continue; 3637 } 3638 3639 if (ch == '{') 3640 { 3641 ++braceCount; 3642 continue; 3643 } 3644 if (ch == '}') 3645 { 3646 --braceCount; 3647 if (braceCount == 0) 3648 { 3649 // is this an array? 3650 if (parenStack->back() == 0 && prevCh != '}') 3651 { 3652 size_t peekNum = line.find_first_not_of(" \t", i + 1); 3653 if (peekNum != string::npos && line[peekNum] == ',') 3654 return 2; 3655 } 3656 if (!hasText) 3657 return 3; // is an empty block 3658 return 1; 3659 } 3660 } 3661 if (ch == ';') 3662 continue; 3663 if (!isWhiteSpace(ch)) 3664 { 3665 hasText = true; 3666 prevCh = ch; 3667 } 3668 } 3669 3670 return 0; 3671 } 3672 3673 /** 3674 * peek at the next word to determine if it is a C# non-paren header. 3675 * will look ahead in the input file if necessary. 3676 * 3677 * @param startChar position on currentLine to start the search 3678 * @return true if the next word is get or set. 3679 */ 3680 bool ASFormatter::isNextWordSharpNonParenHeader(int startChar) const 3681 { 3682 // look ahead to find the next non-comment text 3683 string nextText = peekNextText(currentLine.substr(startChar)); 3684 if (nextText.length() == 0) 3685 return false; 3686 if (nextText[0] == '[') 3687 return true; 3688 if (!isCharPotentialHeader(nextText, 0)) 3689 return false; 3690 if (findKeyword(nextText, 0, AS_GET) || findKeyword(nextText, 0, AS_SET) 3691 || findKeyword(nextText, 0, AS_ADD) || findKeyword(nextText, 0, AS_REMOVE)) 3692 return true; 3693 return false; 3694 } 3695 3696 /** 3697 * peek at the next char to determine if it is an opening brace. 3698 * will look ahead in the input file if necessary. 3699 * this determines a java static constructor. 3700 * 3701 * @param startChar position on currentLine to start the search 3702 * @return true if the next word is an opening brace. 3703 */ 3704 bool ASFormatter::isNextCharOpeningBrace(int startChar) const 3705 { 3706 bool retVal = false; 3707 string nextText = peekNextText(currentLine.substr(startChar)); 3708 if (nextText.length() > 0 3709 && nextText.compare(0, 1, "{") == 0) 3710 retVal = true; 3711 return retVal; 3712 } 3713 3714 /** 3715 * Check if operator and, pointer, and reference padding is disabled. 3716 * Disabling is done thru a NOPAD tag in an ending comment. 3717 * 3718 * @return true if the formatting on this line is disabled. 3719 */ 3720 bool ASFormatter::isOperatorPaddingDisabled() const 3721 { 3722 size_t commentStart = currentLine.find("//", charNum); 3723 if (commentStart == string::npos) 3724 { 3725 commentStart = currentLine.find("/*", charNum); 3726 // comment must end on this line 3727 if (commentStart != string::npos) 3728 { 3729 size_t commentEnd = currentLine.find("*/", commentStart + 2); 3730 if (commentEnd == string::npos) 3731 commentStart = string::npos; 3732 } 3733 } 3734 if (commentStart == string::npos) 3735 return false; 3736 size_t noPadStart = currentLine.find("*NOPAD*", commentStart); 3737 if (noPadStart == string::npos) 3738 return false; 3739 return true; 3740 } 3741 3742 /** 3743 * Determine if an opening array-type brace should have a leading space pad. 3744 * This is to identify C++11 uniform initializers. 3745 */ 3746 bool ASFormatter::isUniformInitializerBrace() const 3747 { 3748 if (isCStyle() && !isInEnum && !isImmediatelyPostPreprocessor) 3749 { 3750 if (isInClassInitializer 3751 || isLegalNameChar(previousNonWSChar) 3752 || previousNonWSChar == '(') 3753 return true; 3754 } 3755 return false; 3756 } 3757 3758 /** 3759 * Determine if there is a following statement on the current line. 3760 */ 3761 bool ASFormatter::isMultiStatementLine() const 3762 { 3763 assert((isImmediatelyPostHeader || foundClosingHeader)); 3764 bool isInComment_ = false; 3765 bool isInQuote_ = false; 3766 int semiCount_ = 0; 3767 int parenCount_ = 0; 3768 int braceCount_ = 0; 3769 3770 for (size_t i = 0; i < currentLine.length(); i++) 3771 { 3772 if (isInComment_) 3773 { 3774 if (currentLine.compare(i, 2, "*/") == 0) 3775 { 3776 isInComment_ = false; 3777 continue; 3778 } 3779 } 3780 if (currentLine.compare(i, 2, "/*") == 0) 3781 { 3782 isInComment_ = true; 3783 continue; 3784 } 3785 if (currentLine.compare(i, 2, "//") == 0) 3786 return false; 3787 if (isInQuote_) 3788 { 3789 if (currentLine[i] == '"' || currentLine[i] == '\'') 3790 isInQuote_ = false; 3791 continue; 3792 } 3793 if (currentLine[i] == '"' || currentLine[i] == '\'') 3794 { 3795 isInQuote_ = true; 3796 continue; 3797 } 3798 if (currentLine[i] == '(') 3799 { 3800 ++parenCount_; 3801 continue; 3802 } 3803 if (currentLine[i] == ')') 3804 { 3805 --parenCount_; 3806 continue; 3807 } 3808 if (parenCount_ > 0) 3809 continue; 3810 if (currentLine[i] == '{') 3811 { 3812 ++braceCount_; 3813 } 3814 if (currentLine[i] == '}') 3815 { 3816 --braceCount_; 3817 } 3818 if (braceCount_ > 0) 3819 continue; 3820 if (currentLine[i] == ';') 3821 { 3822 ++semiCount_; 3823 if (semiCount_ > 1) 3824 return true; 3825 continue; 3826 } 3827 } 3828 return false; 3829 } 3830 3831 /** 3832 * get the next non-whitespace substring on following lines, bypassing all comments. 3833 * 3834 * @param firstLine the first line to check 3835 * @return the next non-whitespace substring. 3836 */ 3837 string ASFormatter::peekNextText(const string& firstLine, 3838 bool endOnEmptyLine /*false*/, 3839 shared_ptr<ASPeekStream> streamArg /*nullptr*/) const 3840 { 3841 assert(sourceIterator->getPeekStart() == 0 || streamArg != nullptr); // Borland may need != 0 3842 bool isFirstLine = true; 3843 string nextLine_ = firstLine; 3844 size_t firstChar = string::npos; 3845 shared_ptr<ASPeekStream> stream = streamArg; 3846 if (stream == nullptr) // Borland may need == 0 3847 stream = make_shared<ASPeekStream>(sourceIterator); 3848 3849 // find the first non-blank text, bypassing all comments. 3850 bool isInComment_ = false; 3851 while (stream->hasMoreLines() || isFirstLine) 3852 { 3853 if (isFirstLine) 3854 isFirstLine = false; 3855 else 3856 nextLine_ = stream->peekNextLine(); 3857 3858 firstChar = nextLine_.find_first_not_of(" \t"); 3859 if (firstChar == string::npos) 3860 { 3861 if (endOnEmptyLine && !isInComment_) 3862 break; 3863 continue; 3864 } 3865 3866 if (nextLine_.compare(firstChar, 2, "/*") == 0) 3867 { 3868 firstChar += 2; 3869 isInComment_ = true; 3870 } 3871 3872 if (isInComment_) 3873 { 3874 firstChar = nextLine_.find("*/", firstChar); 3875 if (firstChar == string::npos) 3876 continue; 3877 firstChar += 2; 3878 isInComment_ = false; 3879 firstChar = nextLine_.find_first_not_of(" \t", firstChar); 3880 if (firstChar == string::npos) 3881 continue; 3882 } 3883 3884 if (nextLine_.compare(firstChar, 2, "//") == 0) 3885 continue; 3886 3887 // found the next text 3888 break; 3889 } 3890 3891 if (firstChar == string::npos) 3892 nextLine_ = ""; 3893 else 3894 nextLine_ = nextLine_.substr(firstChar); 3895 return nextLine_; 3896 } 3897 3898 /** 3899 * adjust comment position because of adding or deleting spaces 3900 * the spaces are added or deleted to formattedLine 3901 * spacePadNum contains the adjustment 3902 */ 3903 void ASFormatter::adjustComments() 3904 { 3905 assert(spacePadNum != 0); 3906 assert(isSequenceReached("//") || isSequenceReached("/*")); 3907 3908 // block comment must be closed on this line with nothing after it 3909 if (isSequenceReached("/*")) 3910 { 3911 size_t endNum = currentLine.find("*/", charNum + 2); 3912 if (endNum == string::npos) 3913 return; 3914 // following line comments may be a tag from AStyleWx //[[)> 3915 size_t nextNum = currentLine.find_first_not_of(" \t", endNum + 2); 3916 if (nextNum != string::npos 3917 && currentLine.compare(nextNum, 2, "//") != 0) 3918 return; 3919 } 3920 3921 size_t len = formattedLine.length(); 3922 // don't adjust a tab 3923 if (formattedLine[len - 1] == '\t') 3924 return; 3925 // if spaces were removed, need to add spaces before the comment 3926 if (spacePadNum < 0) 3927 { 3928 int adjust = -spacePadNum; // make the number positive 3929 formattedLine.append(adjust, ' '); 3930 } 3931 // if spaces were added, need to delete extra spaces before the comment 3932 // if cannot be done put the comment one space after the last text 3933 else if (spacePadNum > 0) 3934 { 3935 int adjust = spacePadNum; 3936 size_t lastText = formattedLine.find_last_not_of(' '); 3937 if (lastText != string::npos 3938 && lastText < len - adjust - 1) 3939 formattedLine.resize(len - adjust); 3940 else if (len > lastText + 2) 3941 formattedLine.resize(lastText + 2); 3942 else if (len < lastText + 2) 3943 formattedLine.append(len - lastText, ' '); 3944 } 3945 } 3946 3947 /** 3948 * append the current brace inside the end of line comments 3949 * currentChar contains the brace, it will be appended to formattedLine 3950 * formattedLineCommentNum is the comment location on formattedLine 3951 */ 3952 void ASFormatter::appendCharInsideComments() 3953 { 3954 if (formattedLineCommentNum == string::npos // does the comment start on the previous line? 3955 || formattedLineCommentNum == 0) 3956 { 3957 appendCurrentChar(); // don't attach 3958 return; 3959 } 3960 assert(formattedLine.compare(formattedLineCommentNum, 2, "//") == 0 3961 || formattedLine.compare(formattedLineCommentNum, 2, "/*") == 0); 3962 3963 // find the previous non space char 3964 size_t end = formattedLineCommentNum; 3965 size_t beg = formattedLine.find_last_not_of(" \t", end - 1); 3966 if (beg == string::npos) 3967 { 3968 appendCurrentChar(); // don't attach 3969 return; 3970 } 3971 beg++; 3972 3973 // insert the brace 3974 if (end - beg < 3) // is there room to insert? 3975 formattedLine.insert(beg, 3 - end + beg, ' '); 3976 if (formattedLine[beg] == '\t') // don't pad with a tab 3977 formattedLine.insert(beg, 1, ' '); 3978 formattedLine[beg + 1] = currentChar; 3979 testForTimeToSplitFormattedLine(); 3980 3981 if (isBeforeComment()) 3982 breakLine(); 3983 else if (isCharImmediatelyPostLineComment) 3984 shouldBreakLineAtNextChar = true; 3985 } 3986 3987 /** 3988 * add or remove space padding to operators 3989 * the operators and necessary padding will be appended to formattedLine 3990 * the calling function should have a continue statement after calling this method 3991 * 3992 * @param newOperator the operator to be padded 3993 */ 3994 void ASFormatter::padOperators(const string* newOperator) 3995 { 3996 assert(shouldPadOperators); 3997 assert(newOperator != nullptr); 3998 3999 char nextNonWSChar = ASBase::peekNextChar(currentLine, charNum); 4000 bool shouldPad = (newOperator != &AS_SCOPE_RESOLUTION 4001 && newOperator != &AS_PLUS_PLUS 4002 && newOperator != &AS_MINUS_MINUS 4003 && newOperator != &AS_NOT 4004 && newOperator != &AS_BIT_NOT 4005 && newOperator != &AS_ARROW 4006 && !(newOperator == &AS_COLON && !foundQuestionMark // objC methods 4007 && (isInObjCMethodDefinition || isInObjCInterface 4008 || isInObjCSelector || squareBracketCount != 0)) 4009 && !(newOperator == &AS_MINUS && isInExponent()) 4010 && !(newOperator == &AS_PLUS && isInExponent()) 4011 && !((newOperator == &AS_PLUS || newOperator == &AS_MINUS) // check for unary plus or minus 4012 && (previousNonWSChar == '(' 4013 || previousNonWSChar == '[' 4014 || previousNonWSChar == '=' 4015 || previousNonWSChar == ',' 4016 || previousNonWSChar == ':' 4017 || previousNonWSChar == '{')) 4018 //? // commented out in release 2.05.1 - doesn't seem to do anything??? 4019 //x && !((newOperator == &AS_MULT || newOperator == &AS_BIT_AND || newOperator == &AS_AND) 4020 //x && isPointerOrReference()) 4021 && !(newOperator == &AS_MULT 4022 && (previousNonWSChar == '.' 4023 || previousNonWSChar == '>')) // check for -> 4024 && !(newOperator == &AS_MULT && peekNextChar() == '>') 4025 && !((isInTemplate || isImmediatelyPostTemplate) 4026 && (newOperator == &AS_LS || newOperator == &AS_GR)) 4027 && !(newOperator == &AS_GCC_MIN_ASSIGN 4028 && ASBase::peekNextChar(currentLine, charNum + 1) == '>') 4029 && !(newOperator == &AS_GR && previousNonWSChar == '?') 4030 && !(newOperator == &AS_QUESTION // check for Java wildcard 4031 && isJavaStyle() 4032 && (previousNonWSChar == '<' 4033 || nextNonWSChar == '>' 4034 || nextNonWSChar == '.')) 4035 && !(newOperator == &AS_QUESTION // check for C# null conditional operator 4036 && isSharpStyle() 4037 && (nextNonWSChar == '.' 4038 || nextNonWSChar == '[')) 4039 && !isCharImmediatelyPostOperator 4040 && !isInCase 4041 && !isInAsm 4042 && !isInAsmOneLine 4043 && !isInAsmBlock 4044 ); 4045 4046 // pad before operator 4047 if (shouldPad 4048 && !(newOperator == &AS_COLON 4049 && (!foundQuestionMark && !isInEnum) && currentHeader != &AS_FOR) 4050 && !(newOperator == &AS_QUESTION && isSharpStyle() // check for C# nullable type (e.g. int?) 4051 && currentLine.find(':', charNum + 1) == string::npos) 4052 ) 4053 appendSpacePad(); 4054 appendOperator(*newOperator); 4055 goForward(newOperator->length() - 1); 4056 4057 currentChar = (*newOperator)[newOperator->length() - 1]; 4058 // pad after operator 4059 // but do not pad after a '-' that is a unary-minus. 4060 if (shouldPad 4061 && !isBeforeAnyComment() 4062 && !(newOperator == &AS_PLUS && isUnaryOperator()) 4063 && !(newOperator == &AS_MINUS && isUnaryOperator()) 4064 && !(currentLine.compare(charNum + 1, 1, AS_SEMICOLON) == 0) 4065 && !(currentLine.compare(charNum + 1, 2, AS_SCOPE_RESOLUTION) == 0) 4066 && !(peekNextChar() == ',') 4067 && !(newOperator == &AS_QUESTION && isSharpStyle() // check for C# nullable type (e.g. int?) 4068 && peekNextChar() == '[') 4069 ) 4070 appendSpaceAfter(); 4071 } 4072 4073 /** 4074 * format pointer or reference 4075 * currentChar contains the pointer or reference 4076 * the symbol and necessary padding will be appended to formattedLine 4077 * the calling function should have a continue statement after calling this method 4078 * 4079 * NOTE: Do NOT use appendCurrentChar() in this method. The line should not be 4080 * broken once the calculation starts. 4081 */ 4082 void ASFormatter::formatPointerOrReference() 4083 { 4084 assert(currentChar == '*' || currentChar == '&' || currentChar == '^'); 4085 assert(!isJavaStyle()); 4086 4087 int pa = pointerAlignment; 4088 int ra = referenceAlignment; 4089 int itemAlignment = (currentChar == '*' || currentChar == '^') 4090 ? pa : ((ra == REF_SAME_AS_PTR) ? pa : ra); 4091 4092 // check for ** and && 4093 int ptrLength = 1; 4094 char peekedChar = peekNextChar(); 4095 if ((currentChar == '*' && peekedChar == '*') 4096 || (currentChar == '&' && peekedChar == '&')) 4097 { 4098 ptrLength = 2; 4099 size_t nextChar = currentLine.find_first_not_of(" \t", charNum + 2); 4100 if (nextChar == string::npos) 4101 peekedChar = ' '; 4102 else 4103 peekedChar = currentLine[nextChar]; 4104 } 4105 // check for cast 4106 if (peekedChar == ')' || peekedChar == '>' || peekedChar == ',') 4107 { 4108 formatPointerOrReferenceCast(); 4109 return; 4110 } 4111 4112 // check for a padded space and remove it 4113 if (charNum > 0 4114 && !isWhiteSpace(currentLine[charNum - 1]) 4115 && formattedLine.length() > 0 4116 && isWhiteSpace(formattedLine[formattedLine.length() - 1])) 4117 { 4118 formattedLine.erase(formattedLine.length() - 1); 4119 spacePadNum--; 4120 } 4121 4122 if (itemAlignment == PTR_ALIGN_TYPE) 4123 { 4124 formatPointerOrReferenceToType(); 4125 } 4126 else if (itemAlignment == PTR_ALIGN_MIDDLE) 4127 { 4128 formatPointerOrReferenceToMiddle(); 4129 } 4130 else if (itemAlignment == PTR_ALIGN_NAME) 4131 { 4132 formatPointerOrReferenceToName(); 4133 } 4134 else // pointerAlignment == PTR_ALIGN_NONE 4135 { 4136 formattedLine.append(currentLine.substr(charNum, ptrLength)); 4137 if (ptrLength > 1) 4138 goForward(ptrLength - 1); 4139 } 4140 } 4141 4142 /** 4143 * format pointer or reference with align to type 4144 */ 4145 void ASFormatter::formatPointerOrReferenceToType() 4146 { 4147 assert(currentChar == '*' || currentChar == '&' || currentChar == '^'); 4148 assert(!isJavaStyle()); 4149 4150 // do this before bumping charNum 4151 bool isOldPRCentered = isPointerOrReferenceCentered(); 4152 string sequenceToInsert(1, currentChar); 4153 // get the sequence 4154 if (currentChar == peekNextChar()) 4155 { 4156 for (size_t i = charNum + 1; currentLine.length() > i; i++) 4157 { 4158 if (currentLine[i] == sequenceToInsert[0]) 4159 { 4160 sequenceToInsert.append(1, currentLine[i]); 4161 goForward(1); 4162 continue; 4163 } 4164 break; 4165 } 4166 } 4167 // append the seqence 4168 string charSave; 4169 size_t prevCh = formattedLine.find_last_not_of(" \t"); 4170 if (prevCh < formattedLine.length()) 4171 { 4172 charSave = formattedLine.substr(prevCh + 1); 4173 formattedLine.resize(prevCh + 1); 4174 } 4175 formattedLine.append(sequenceToInsert); 4176 if (peekNextChar() != ')') 4177 formattedLine.append(charSave); 4178 else 4179 spacePadNum -= charSave.length(); 4180 // if no space after then add one 4181 if (charNum < (int) currentLine.length() - 1 4182 && !isWhiteSpace(currentLine[charNum + 1]) 4183 && currentLine[charNum + 1] != ')') 4184 appendSpacePad(); 4185 // if old pointer or reference is centered, remove a space 4186 if (isOldPRCentered 4187 && isWhiteSpace(formattedLine[formattedLine.length() - 1])) 4188 { 4189 formattedLine.erase(formattedLine.length() - 1, 1); 4190 spacePadNum--; 4191 } 4192 // update the formattedLine split point 4193 if (maxCodeLength != string::npos && formattedLine.length() > 0) 4194 { 4195 size_t index = formattedLine.length() - 1; 4196 if (isWhiteSpace(formattedLine[index])) 4197 { 4198 updateFormattedLineSplitPointsPointerOrReference(index); 4199 testForTimeToSplitFormattedLine(); 4200 } 4201 } 4202 } 4203 4204 /** 4205 * format pointer or reference with align in the middle 4206 */ 4207 void ASFormatter::formatPointerOrReferenceToMiddle() 4208 { 4209 assert(currentChar == '*' || currentChar == '&' || currentChar == '^'); 4210 assert(!isJavaStyle()); 4211 4212 // compute current whitespace before 4213 size_t wsBefore = currentLine.find_last_not_of(" \t", charNum - 1); 4214 if (wsBefore == string::npos) 4215 wsBefore = 0; 4216 else 4217 wsBefore = charNum - wsBefore - 1; 4218 string sequenceToInsert(1, currentChar); 4219 if (currentChar == peekNextChar()) 4220 { 4221 for (size_t i = charNum + 1; currentLine.length() > i; i++) 4222 { 4223 if (currentLine[i] == sequenceToInsert[0]) 4224 { 4225 sequenceToInsert.append(1, currentLine[i]); 4226 goForward(1); 4227 continue; 4228 } 4229 break; 4230 } 4231 } 4232 // if reference to a pointer check for conflicting alignment 4233 else if (currentChar == '*' && peekNextChar() == '&' 4234 && (referenceAlignment == REF_ALIGN_TYPE 4235 || referenceAlignment == REF_ALIGN_MIDDLE 4236 || referenceAlignment == REF_SAME_AS_PTR)) 4237 { 4238 sequenceToInsert = "*&"; 4239 goForward(1); 4240 for (size_t i = charNum; i < currentLine.length() - 1 && isWhiteSpace(currentLine[i]); i++) 4241 goForward(1); 4242 } 4243 // if a comment follows don't align, just space pad 4244 if (isBeforeAnyComment()) 4245 { 4246 appendSpacePad(); 4247 formattedLine.append(sequenceToInsert); 4248 appendSpaceAfter(); 4249 return; 4250 } 4251 // do this before goForward() 4252 bool isAfterScopeResolution = previousNonWSChar == ':'; 4253 size_t charNumSave = charNum; 4254 // if this is the last thing on the line 4255 if (currentLine.find_first_not_of(" \t", charNum + 1) == string::npos) 4256 { 4257 if (wsBefore == 0 && !isAfterScopeResolution) 4258 formattedLine.append(1, ' '); 4259 formattedLine.append(sequenceToInsert); 4260 return; 4261 } 4262 // goForward() to convert tabs to spaces, if necessary, 4263 // and move following characters to preceding characters 4264 // this may not work every time with tab characters 4265 for (size_t i = charNum + 1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++) 4266 { 4267 goForward(1); 4268 if (formattedLine.length() > 0) 4269 formattedLine.append(1, currentLine[i]); 4270 else 4271 spacePadNum--; 4272 } 4273 // find space padding after 4274 size_t wsAfter = currentLine.find_first_not_of(" \t", charNumSave + 1); 4275 if (wsAfter == string::npos || isBeforeAnyComment()) 4276 wsAfter = 0; 4277 else 4278 wsAfter = wsAfter - charNumSave - 1; 4279 // don't pad before scope resolution operator, but pad after 4280 if (isAfterScopeResolution) 4281 { 4282 size_t lastText = formattedLine.find_last_not_of(" \t"); 4283 formattedLine.insert(lastText + 1, sequenceToInsert); 4284 appendSpacePad(); 4285 } 4286 else if (formattedLine.length() > 0) 4287 { 4288 // whitespace should be at least 2 chars to center 4289 if (wsBefore + wsAfter < 2) 4290 { 4291 size_t charsToAppend = (2 - (wsBefore + wsAfter)); 4292 formattedLine.append(charsToAppend, ' '); 4293 spacePadNum += charsToAppend; 4294 if (wsBefore == 0) 4295 wsBefore++; 4296 if (wsAfter == 0) 4297 wsAfter++; 4298 } 4299 // insert the pointer or reference char 4300 size_t padAfter = (wsBefore + wsAfter) / 2; 4301 size_t index = formattedLine.length() - padAfter; 4302 if (index < formattedLine.length()) 4303 formattedLine.insert(index, sequenceToInsert); 4304 else 4305 formattedLine.append(sequenceToInsert); 4306 } 4307 else // formattedLine.length() == 0 4308 { 4309 formattedLine.append(sequenceToInsert); 4310 if (wsAfter == 0) 4311 wsAfter++; 4312 formattedLine.append(wsAfter, ' '); 4313 spacePadNum += wsAfter; 4314 } 4315 // update the formattedLine split point after the pointer 4316 if (maxCodeLength != string::npos && formattedLine.length() > 0) 4317 { 4318 size_t index = formattedLine.find_last_not_of(" \t"); 4319 if (index != string::npos && (index < formattedLine.length() - 1)) 4320 { 4321 index++; 4322 updateFormattedLineSplitPointsPointerOrReference(index); 4323 testForTimeToSplitFormattedLine(); 4324 } 4325 } 4326 } 4327 4328 /** 4329 * format pointer or reference with align to name 4330 */ 4331 void ASFormatter::formatPointerOrReferenceToName() 4332 { 4333 assert(currentChar == '*' || currentChar == '&' || currentChar == '^'); 4334 assert(!isJavaStyle()); 4335 4336 // do this before bumping charNum 4337 bool isOldPRCentered = isPointerOrReferenceCentered(); 4338 4339 size_t startNum = formattedLine.find_last_not_of(" \t"); 4340 if (startNum == string::npos) 4341 startNum = 0; 4342 string sequenceToInsert(1, currentChar); 4343 if (currentChar == peekNextChar()) 4344 { 4345 for (size_t i = charNum + 1; currentLine.length() > i; i++) 4346 { 4347 if (currentLine[i] == sequenceToInsert[0]) 4348 { 4349 sequenceToInsert.append(1, currentLine[i]); 4350 goForward(1); 4351 continue; 4352 } 4353 break; 4354 } 4355 } 4356 // if reference to a pointer align both to name 4357 else if (currentChar == '*' && peekNextChar() == '&') 4358 { 4359 sequenceToInsert = "*&"; 4360 goForward(1); 4361 for (size_t i = charNum; i < currentLine.length() - 1 && isWhiteSpace(currentLine[i]); i++) 4362 goForward(1); 4363 } 4364 char peekedChar = peekNextChar(); 4365 bool isAfterScopeResolution = previousNonWSChar == ':'; // check for :: 4366 // if this is not the last thing on the line 4367 if ((isLegalNameChar(peekedChar) || peekedChar == '(' || peekedChar == '[' || peekedChar == '=') 4368 && (int) currentLine.find_first_not_of(" \t", charNum + 1) > charNum) 4369 { 4370 // goForward() to convert tabs to spaces, if necessary, 4371 // and move following characters to preceding characters 4372 // this may not work every time with tab characters 4373 for (size_t i = charNum + 1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++) 4374 { 4375 // if a padded paren follows don't move 4376 if (shouldPadParensOutside && peekedChar == '(' && !isOldPRCentered) 4377 { 4378 // empty parens don't count 4379 size_t start = currentLine.find_first_not_of("( \t", i); 4380 if (start != string::npos && currentLine[start] != ')') 4381 break; 4382 } 4383 goForward(1); 4384 if (formattedLine.length() > 0) 4385 formattedLine.append(1, currentLine[charNum]); 4386 else 4387 spacePadNum--; 4388 } 4389 } 4390 // don't pad before scope resolution operator 4391 if (isAfterScopeResolution) 4392 { 4393 size_t lastText = formattedLine.find_last_not_of(" \t"); 4394 if (lastText != string::npos && lastText + 1 < formattedLine.length()) 4395 formattedLine.erase(lastText + 1); 4396 } 4397 // if no space before * then add one 4398 else if (formattedLine.length() > 0 4399 && (formattedLine.length() <= startNum + 1 4400 || !isWhiteSpace(formattedLine[startNum + 1]))) 4401 { 4402 formattedLine.insert(startNum + 1, 1, ' '); 4403 spacePadNum++; 4404 } 4405 appendSequence(sequenceToInsert, false); 4406 // if old pointer or reference is centered, remove a space 4407 if (isOldPRCentered 4408 && formattedLine.length() > startNum + 1 4409 && isWhiteSpace(formattedLine[startNum + 1]) 4410 && peekedChar != '*' // check for '* *' 4411 && !isBeforeAnyComment()) 4412 { 4413 formattedLine.erase(startNum + 1, 1); 4414 spacePadNum--; 4415 } 4416 // don't convert to *= or &= 4417 if (peekedChar == '=') 4418 { 4419 appendSpaceAfter(); 4420 // if more than one space before, delete one 4421 if (formattedLine.length() > startNum 4422 && isWhiteSpace(formattedLine[startNum + 1]) 4423 && isWhiteSpace(formattedLine[startNum + 2])) 4424 { 4425 formattedLine.erase(startNum + 1, 1); 4426 spacePadNum--; 4427 } 4428 } 4429 // update the formattedLine split point 4430 if (maxCodeLength != string::npos) 4431 { 4432 size_t index = formattedLine.find_last_of(" \t"); 4433 if (index != string::npos 4434 && index < formattedLine.length() - 1 4435 && (formattedLine[index + 1] == '*' 4436 || formattedLine[index + 1] == '&' 4437 || formattedLine[index + 1] == '^')) 4438 { 4439 updateFormattedLineSplitPointsPointerOrReference(index); 4440 testForTimeToSplitFormattedLine(); 4441 } 4442 } 4443 } 4444 4445 /** 4446 * format pointer or reference cast 4447 * currentChar contains the pointer or reference 4448 * NOTE: the pointers and references in function definitions 4449 * are processed as a cast (e.g. void foo(void*, void*)) 4450 * is processed here. 4451 */ 4452 void ASFormatter::formatPointerOrReferenceCast() 4453 { 4454 assert(currentChar == '*' || currentChar == '&' || currentChar == '^'); 4455 assert(!isJavaStyle()); 4456 4457 int pa = pointerAlignment; 4458 int ra = referenceAlignment; 4459 int itemAlignment = (currentChar == '*' || currentChar == '^') 4460 ? pa : ((ra == REF_SAME_AS_PTR) ? pa : ra); 4461 4462 string sequenceToInsert(1, currentChar); 4463 if (isSequenceReached("**") || isSequenceReached("&&")) 4464 { 4465 goForward(1); 4466 sequenceToInsert.append(1, currentLine[charNum]); 4467 } 4468 if (itemAlignment == PTR_ALIGN_NONE) 4469 { 4470 appendSequence(sequenceToInsert, false); 4471 return; 4472 } 4473 // remove preceding whitespace 4474 char prevCh = ' '; 4475 size_t prevNum = formattedLine.find_last_not_of(" \t"); 4476 if (prevNum != string::npos) 4477 { 4478 prevCh = formattedLine[prevNum]; 4479 if (itemAlignment == PTR_ALIGN_TYPE && currentChar == '*' && prevCh == '*') 4480 { 4481 // '* *' may be a multiply followed by a dereference 4482 if (prevNum + 2 < formattedLine.length() 4483 && isWhiteSpace(formattedLine[prevNum + 2])) 4484 { 4485 spacePadNum -= (formattedLine.length() - 2 - prevNum); 4486 formattedLine.erase(prevNum + 2); 4487 } 4488 } 4489 else if (prevNum + 1 < formattedLine.length() 4490 && isWhiteSpace(formattedLine[prevNum + 1]) 4491 && prevCh != '(') 4492 { 4493 spacePadNum -= (formattedLine.length() - 1 - prevNum); 4494 formattedLine.erase(prevNum + 1); 4495 } 4496 } 4497 bool isAfterScopeResolution = previousNonWSChar == ':'; 4498 if ((itemAlignment == PTR_ALIGN_MIDDLE || itemAlignment == PTR_ALIGN_NAME) 4499 && !isAfterScopeResolution && prevCh != '(') 4500 { 4501 appendSpacePad(); 4502 // in this case appendSpacePad may or may not update the split point 4503 if (maxCodeLength != string::npos && formattedLine.length() > 0) 4504 updateFormattedLineSplitPointsPointerOrReference(formattedLine.length() - 1); 4505 appendSequence(sequenceToInsert, false); 4506 } 4507 else 4508 appendSequence(sequenceToInsert, false); 4509 } 4510 4511 /** 4512 * add or remove space padding to parens 4513 * currentChar contains the paren 4514 * the parens and necessary padding will be appended to formattedLine 4515 * the calling function should have a continue statement after calling this method 4516 */ 4517 void ASFormatter::padParens() 4518 { 4519 assert(currentChar == '(' || currentChar == ')'); 4520 assert(shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens || shouldPadFirstParen); 4521 4522 int spacesOutsideToDelete = 0; 4523 int spacesInsideToDelete = 0; 4524 4525 if (currentChar == '(') 4526 { 4527 spacesOutsideToDelete = formattedLine.length() - 1; 4528 spacesInsideToDelete = 0; 4529 4530 // compute spaces outside the opening paren to delete 4531 if (shouldUnPadParens) 4532 { 4533 char lastChar = ' '; 4534 bool prevIsParenHeader = false; 4535 size_t i = formattedLine.find_last_not_of(" \t"); 4536 if (i != string::npos) 4537 { 4538 // if last char is a brace the previous whitespace is an indent 4539 if (formattedLine[i] == '{') 4540 spacesOutsideToDelete = 0; 4541 else if (isCharImmediatelyPostPointerOrReference) 4542 spacesOutsideToDelete = 0; 4543 else 4544 { 4545 spacesOutsideToDelete -= i; 4546 lastChar = formattedLine[i]; 4547 // if previous word is a header, it will be a paren header 4548 string prevWord = getPreviousWord(formattedLine, formattedLine.length()); 4549 const string* prevWordH = nullptr; 4550 if (shouldPadHeader 4551 && prevWord.length() > 0 4552 && isCharPotentialHeader(prevWord, 0)) 4553 prevWordH = ASBase::findHeader(prevWord, 0, headers); 4554 if (prevWordH != nullptr) 4555 prevIsParenHeader = true; // don't unpad 4556 else if (prevWord == AS_RETURN) 4557 prevIsParenHeader = true; // don't unpad 4558 else if ((prevWord == AS_NEW || prevWord == AS_DELETE) 4559 && shouldPadHeader) 4560 prevIsParenHeader = true; // don't unpad 4561 else if (isCStyle() && prevWord == AS_THROW && shouldPadHeader) 4562 prevIsParenHeader = true; // don't unpad 4563 else if (prevWord == "and" || prevWord == "or" || prevWord == "in") 4564 prevIsParenHeader = true; // don't unpad 4565 // don't unpad variables 4566 else if (isNumericVariable(prevWord)) 4567 prevIsParenHeader = true; // don't unpad 4568 } 4569 } 4570 // do not unpad operators, but leave them if already padded 4571 if (shouldPadParensOutside || prevIsParenHeader) 4572 spacesOutsideToDelete--; 4573 else if (lastChar == '|' // check for || 4574 || lastChar == '&' // check for && 4575 || lastChar == ',' 4576 || (lastChar == '(' && shouldPadParensInside) 4577 || (lastChar == '>' && !foundCastOperator) 4578 || lastChar == '<' 4579 || lastChar == '?' 4580 || lastChar == ':' 4581 || lastChar == ';' 4582 || lastChar == '=' 4583 || lastChar == '+' 4584 || lastChar == '-' 4585 || lastChar == '*' 4586 || lastChar == '/' 4587 || lastChar == '%' 4588 || lastChar == '^' 4589 ) 4590 spacesOutsideToDelete--; 4591 4592 if (spacesOutsideToDelete > 0) 4593 { 4594 formattedLine.erase(i + 1, spacesOutsideToDelete); 4595 spacePadNum -= spacesOutsideToDelete; 4596 } 4597 } 4598 4599 // pad open paren outside 4600 char peekedCharOutside = peekNextChar(); 4601 if (shouldPadFirstParen && previousChar != '(' && peekedCharOutside != ')') 4602 appendSpacePad(); 4603 else if (shouldPadParensOutside) 4604 { 4605 if (!(currentChar == '(' && peekedCharOutside == ')')) 4606 appendSpacePad(); 4607 } 4608 4609 appendCurrentChar(); 4610 4611 // unpad open paren inside 4612 if (shouldUnPadParens) 4613 { 4614 size_t j = currentLine.find_first_not_of(" \t", charNum + 1); 4615 if (j != string::npos) 4616 spacesInsideToDelete = j - charNum - 1; 4617 if (shouldPadParensInside) 4618 spacesInsideToDelete--; 4619 if (spacesInsideToDelete > 0) 4620 { 4621 currentLine.erase(charNum + 1, spacesInsideToDelete); 4622 spacePadNum -= spacesInsideToDelete; 4623 } 4624 // convert tab to space if requested 4625 if (shouldConvertTabs 4626 && (int) currentLine.length() > charNum + 1 4627 && currentLine[charNum + 1] == '\t') 4628 currentLine[charNum + 1] = ' '; 4629 } 4630 4631 // pad open paren inside 4632 char peekedCharInside = peekNextChar(); 4633 if (shouldPadParensInside) 4634 if (!(currentChar == '(' && peekedCharInside == ')')) 4635 appendSpaceAfter(); 4636 } 4637 else if (currentChar == ')') 4638 { 4639 // unpad close paren inside 4640 if (shouldUnPadParens) 4641 { 4642 spacesInsideToDelete = formattedLine.length(); 4643 size_t i = formattedLine.find_last_not_of(" \t"); 4644 if (i != string::npos) 4645 spacesInsideToDelete = formattedLine.length() - 1 - i; 4646 if (shouldPadParensInside) 4647 spacesInsideToDelete--; 4648 if (spacesInsideToDelete > 0) 4649 { 4650 formattedLine.erase(i + 1, spacesInsideToDelete); 4651 spacePadNum -= spacesInsideToDelete; 4652 } 4653 } 4654 4655 // pad close paren inside 4656 if (shouldPadParensInside) 4657 if (!(previousChar == '(' && currentChar == ')')) 4658 appendSpacePad(); 4659 4660 appendCurrentChar(); 4661 4662 // unpad close paren outside 4663 // close parens outside are left unchanged 4664 if (shouldUnPadParens) 4665 { 4666 //spacesOutsideToDelete = 0; 4667 //size_t j = currentLine.find_first_not_of(" \t", charNum + 1); 4668 //if (j != string::npos) 4669 // spacesOutsideToDelete = j - charNum - 1; 4670 //if (shouldPadParensOutside) 4671 // spacesOutsideToDelete--; 4672 4673 //if (spacesOutsideToDelete > 0) 4674 //{ 4675 // currentLine.erase(charNum + 1, spacesOutsideToDelete); 4676 // spacePadNum -= spacesOutsideToDelete; 4677 //} 4678 } 4679 4680 // pad close paren outside 4681 char peekedCharOutside = peekNextChar(); 4682 if (shouldPadParensOutside) 4683 if (peekedCharOutside != ';' 4684 && peekedCharOutside != ',' 4685 && peekedCharOutside != '.' 4686 && peekedCharOutside != '+' // check for ++ 4687 && peekedCharOutside != '-' // check for -- 4688 && peekedCharOutside != ']') 4689 appendSpaceAfter(); 4690 } 4691 } 4692 4693 /** 4694 * add or remove space padding to objective-c method prefix (- or +) 4695 * if this is a '(' it begins a return type 4696 * these options have precedence over the padParens methods 4697 * the padParens method has already been called, this method adjusts 4698 */ 4699 void ASFormatter::padObjCMethodPrefix() 4700 { 4701 assert(isInObjCMethodDefinition && isImmediatelyPostObjCMethodPrefix); 4702 assert(shouldPadMethodPrefix || shouldUnPadMethodPrefix); 4703 4704 size_t prefix = formattedLine.find_first_of("+-"); 4705 if (prefix == string::npos) 4706 return; 4707 size_t firstChar = formattedLine.find_first_not_of(" \t", prefix + 1); 4708 if (firstChar == string::npos) 4709 firstChar = formattedLine.length(); 4710 int spaces = firstChar - prefix - 1; 4711 4712 if (shouldPadMethodPrefix) 4713 { 4714 if (spaces == 0) 4715 { 4716 formattedLine.insert(prefix + 1, 1, ' '); 4717 spacePadNum += 1; 4718 } 4719 else if (spaces > 1) 4720 { 4721 formattedLine.erase(prefix + 1, spaces - 1); 4722 formattedLine[prefix + 1] = ' '; // convert any tab to space 4723 spacePadNum -= spaces - 1; 4724 } 4725 } 4726 // this option will be ignored if used with pad-method-prefix 4727 else if (shouldUnPadMethodPrefix) 4728 { 4729 if (spaces > 0) 4730 { 4731 formattedLine.erase(prefix + 1, spaces); 4732 spacePadNum -= spaces; 4733 } 4734 } 4735 } 4736 4737 /** 4738 * add or remove space padding to objective-c parens 4739 * these options have precedence over the padParens methods 4740 * the padParens method has already been called, this method adjusts 4741 */ 4742 void ASFormatter::padObjCReturnType() 4743 { 4744 assert(currentChar == ')' && isInObjCReturnType); 4745 assert(shouldPadReturnType || shouldUnPadReturnType); 4746 4747 size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1); 4748 if (nextText == string::npos) 4749 return; 4750 int spaces = nextText - charNum - 1; 4751 4752 if (shouldPadReturnType) 4753 { 4754 if (spaces == 0) 4755 { 4756 // this will already be padded if pad-paren is used 4757 if (formattedLine[formattedLine.length() - 1] != ' ') 4758 { 4759 formattedLine.append(" "); 4760 spacePadNum += 1; 4761 } 4762 } 4763 else if (spaces > 1) 4764 { 4765 // do not use goForward here 4766 currentLine.erase(charNum + 1, spaces - 1); 4767 currentLine[charNum + 1] = ' '; // convert any tab to space 4768 spacePadNum -= spaces - 1; 4769 } 4770 } 4771 // this option will be ignored if used with pad-return-type 4772 else if (shouldUnPadReturnType) 4773 { 4774 // this will already be padded if pad-paren is used 4775 if (formattedLine[formattedLine.length() - 1] == ' ') 4776 { 4777 int lastText = formattedLine.find_last_not_of(" \t"); 4778 spacePadNum -= formattedLine.length() - lastText - 1; 4779 formattedLine.resize(lastText + 1); 4780 } 4781 // do not use goForward here 4782 currentLine.erase(charNum + 1, spaces); 4783 spacePadNum -= spaces; 4784 } 4785 } 4786 4787 /** 4788 * add or remove space padding to objective-c parens 4789 * these options have precedence over the padParens methods 4790 * the padParens method has already been called, this method adjusts 4791 */ 4792 void ASFormatter::padObjCParamType() 4793 { 4794 assert((currentChar == '(' || currentChar == ')') && isInObjCMethodDefinition); 4795 assert(!isImmediatelyPostObjCMethodPrefix && !isInObjCReturnType); 4796 assert(shouldPadParamType || shouldUnPadParamType); 4797 4798 if (currentChar == '(') 4799 { 4800 // open paren has already been attached to formattedLine by padParen 4801 size_t paramOpen = formattedLine.rfind('('); 4802 assert(paramOpen != string::npos); 4803 size_t prevText = formattedLine.find_last_not_of(" \t", paramOpen - 1); 4804 if (prevText == string::npos) 4805 return; 4806 int spaces = paramOpen - prevText - 1; 4807 4808 if (shouldPadParamType 4809 || objCColonPadMode == COLON_PAD_ALL 4810 || objCColonPadMode == COLON_PAD_AFTER) 4811 { 4812 if (spaces == 0) 4813 { 4814 formattedLine.insert(paramOpen, 1, ' '); 4815 spacePadNum += 1; 4816 } 4817 if (spaces > 1) 4818 { 4819 formattedLine.erase(prevText + 1, spaces - 1); 4820 formattedLine[prevText + 1] = ' '; // convert any tab to space 4821 spacePadNum -= spaces - 1; 4822 } 4823 } 4824 // this option will be ignored if used with pad-param-type 4825 else if (shouldUnPadParamType 4826 || objCColonPadMode == COLON_PAD_NONE 4827 || objCColonPadMode == COLON_PAD_BEFORE) 4828 { 4829 if (spaces > 0) 4830 { 4831 formattedLine.erase(prevText + 1, spaces); 4832 spacePadNum -= spaces; 4833 } 4834 } 4835 } 4836 else if (currentChar == ')') 4837 { 4838 size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1); 4839 if (nextText == string::npos) 4840 return; 4841 int spaces = nextText - charNum - 1; 4842 4843 if (shouldPadParamType) 4844 { 4845 if (spaces == 0) 4846 { 4847 // this will already be padded if pad-paren is used 4848 if (formattedLine[formattedLine.length() - 1] != ' ') 4849 { 4850 formattedLine.append(" "); 4851 spacePadNum += 1; 4852 } 4853 } 4854 else if (spaces > 1) 4855 { 4856 // do not use goForward here 4857 currentLine.erase(charNum + 1, spaces - 1); 4858 currentLine[charNum + 1] = ' '; // convert any tab to space 4859 spacePadNum -= spaces - 1; 4860 } 4861 } 4862 // this option will be ignored if used with pad-param-type 4863 else if (shouldUnPadParamType) 4864 { 4865 // this will already be padded if pad-paren is used 4866 if (formattedLine[formattedLine.length() - 1] == ' ') 4867 { 4868 spacePadNum -= 1; 4869 int lastText = formattedLine.find_last_not_of(" \t"); 4870 formattedLine.resize(lastText + 1); 4871 } 4872 if (spaces > 0) 4873 { 4874 // do not use goForward here 4875 currentLine.erase(charNum + 1, spaces); 4876 spacePadNum -= spaces; 4877 } 4878 } 4879 } 4880 } 4881 4882 /** 4883 * format opening brace as attached or broken 4884 * currentChar contains the brace 4885 * the braces will be appended to the current formattedLine or a new formattedLine as necessary 4886 * the calling function should have a continue statement after calling this method 4887 * 4888 * @param braceType the type of brace to be formatted. 4889 */ 4890 void ASFormatter::formatOpeningBrace(BraceType braceType) 4891 { 4892 assert(!isBraceType(braceType, ARRAY_TYPE)); 4893 assert(currentChar == '{'); 4894 4895 parenStack->emplace_back(0); 4896 4897 bool breakBrace = isCurrentBraceBroken(); 4898 4899 if (breakBrace) 4900 { 4901 if (isBeforeAnyComment() && isOkToBreakBlock(braceType) && sourceIterator->hasMoreLines()) 4902 { 4903 // if comment is at line end leave the comment on this line 4904 if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace) 4905 { 4906 currentChar = ' '; // remove brace from current line 4907 if (parenStack->size() > 1) 4908 parenStack->pop_back(); 4909 currentLine[charNum] = currentChar; 4910 appendOpeningBrace = true; // append brace to following line 4911 } 4912 // else put comment after the brace 4913 else if (!isBeforeMultipleLineEndComments(charNum)) 4914 breakLine(); 4915 } 4916 else if (!isBraceType(braceType, SINGLE_LINE_TYPE)) 4917 { 4918 formattedLine = rtrim(formattedLine); 4919 breakLine(); 4920 } 4921 else if ((shouldBreakOneLineBlocks || isBraceType(braceType, BREAK_BLOCK_TYPE)) 4922 && !isBraceType(braceType, EMPTY_BLOCK_TYPE)) 4923 breakLine(); 4924 else if (!isInLineBreak) 4925 appendSpacePad(); 4926 4927 appendCurrentChar(); 4928 4929 // should a following comment break from the brace? 4930 // must break the line AFTER the brace 4931 if (isBeforeComment() 4932 && formattedLine.length() > 0 4933 && formattedLine[0] == '{' 4934 && isOkToBreakBlock(braceType) 4935 && (braceFormatMode == BREAK_MODE 4936 || braceFormatMode == LINUX_MODE)) 4937 { 4938 shouldBreakLineAtNextChar = true; 4939 } 4940 } 4941 else // attach brace 4942 { 4943 // are there comments before the brace? 4944 if (isCharImmediatelyPostComment || isCharImmediatelyPostLineComment) 4945 { 4946 if (isOkToBreakBlock(braceType) 4947 && !(isCharImmediatelyPostComment && isCharImmediatelyPostLineComment) // don't attach if two comments on the line 4948 && !isImmediatelyPostPreprocessor 4949 // && peekNextChar() != '}' // don't attach { } // removed release 2.03 4950 && previousCommandChar != '{' // don't attach { { 4951 && previousCommandChar != '}' // don't attach } { 4952 && previousCommandChar != ';') // don't attach ; { 4953 { 4954 appendCharInsideComments(); 4955 } 4956 else 4957 { 4958 appendCurrentChar(); // don't attach 4959 } 4960 } 4961 else if (previousCommandChar == '{' 4962 || (previousCommandChar == '}' && !isInClassInitializer) 4963 || previousCommandChar == ';') // '}' , ';' chars added for proper handling of '{' immediately after a '}' or ';' 4964 { 4965 appendCurrentChar(); // don't attach 4966 } 4967 else 4968 { 4969 // if a blank line precedes this don't attach 4970 if (isEmptyLine(formattedLine)) 4971 appendCurrentChar(); // don't attach 4972 else if (isOkToBreakBlock(braceType) 4973 && !(isImmediatelyPostPreprocessor 4974 && currentLineBeginsWithBrace)) 4975 { 4976 if (!isBraceType(braceType, EMPTY_BLOCK_TYPE)) 4977 { 4978 appendSpacePad(); 4979 appendCurrentChar(false); // OK to attach 4980 testForTimeToSplitFormattedLine(); // line length will have changed 4981 // should a following comment attach with the brace? 4982 // insert spaces to reposition the comment 4983 if (isBeforeComment() 4984 && !isBeforeMultipleLineEndComments(charNum) 4985 && (!isBeforeAnyLineEndComment(charNum) || currentLineBeginsWithBrace)) 4986 { 4987 shouldBreakLineAtNextChar = true; 4988 currentLine.insert(charNum + 1, charNum + 1, ' '); 4989 } 4990 else if (!isBeforeAnyComment()) // added in release 2.03 4991 { 4992 shouldBreakLineAtNextChar = true; 4993 } 4994 } 4995 else 4996 { 4997 if (currentLineBeginsWithBrace && (size_t) charNum == currentLineFirstBraceNum) 4998 { 4999 appendSpacePad(); 5000 appendCurrentChar(false); // attach 5001 shouldBreakLineAtNextChar = true; 5002 } 5003 else 5004 { 5005 appendSpacePad(); 5006 appendCurrentChar(); // don't attach 5007 } 5008 } 5009 } 5010 else 5011 { 5012 if (!isInLineBreak) 5013 appendSpacePad(); 5014 appendCurrentChar(); // don't attach 5015 } 5016 } 5017 } 5018 } 5019 5020 /** 5021 * format closing brace 5022 * currentChar contains the brace 5023 * the calling function should have a continue statement after calling this method 5024 * 5025 * @param braceType the type of the opening brace for this closing brace. 5026 */ 5027 void ASFormatter::formatClosingBrace(BraceType braceType) 5028 { 5029 assert(!isBraceType(braceType, ARRAY_TYPE)); 5030 assert(currentChar == '}'); 5031 5032 // parenStack must contain one entry 5033 if (parenStack->size() > 1) 5034 parenStack->pop_back(); 5035 5036 // mark state of immediately after empty block 5037 // this state will be used for locating braces that appear immediately AFTER an empty block (e.g. '{} \n}'). 5038 if (previousCommandChar == '{') 5039 isImmediatelyPostEmptyBlock = true; 5040 5041 if (attachClosingBraceMode) 5042 { 5043 // for now, namespaces and classes will be attached. Uncomment the lines below to break. 5044 if ((isEmptyLine(formattedLine) // if a blank line precedes this 5045 || isCharImmediatelyPostLineComment 5046 || isCharImmediatelyPostComment 5047 || (isImmediatelyPostPreprocessor && (int) currentLine.find_first_not_of(" \t") == charNum) 5048 // || (isBraceType(braceType, CLASS_TYPE) && isOkToBreakBlock(braceType) && previousNonWSChar != '{') 5049 // || (isBraceType(braceType, NAMESPACE_TYPE) && isOkToBreakBlock(braceType) && previousNonWSChar != '{') 5050 ) 5051 && (!isBraceType(braceType, SINGLE_LINE_TYPE) || isOkToBreakBlock(braceType))) 5052 { 5053 breakLine(); 5054 appendCurrentChar(); // don't attach 5055 } 5056 else 5057 { 5058 if (previousNonWSChar != '{' 5059 && (!isBraceType(braceType, SINGLE_LINE_TYPE) 5060 || isOkToBreakBlock(braceType))) 5061 appendSpacePad(); 5062 appendCurrentChar(false); // attach 5063 } 5064 } 5065 else if (!isBraceType(braceType, EMPTY_BLOCK_TYPE) 5066 && (isBraceType(braceType, BREAK_BLOCK_TYPE) 5067 || isOkToBreakBlock(braceType))) 5068 { 5069 breakLine(); 5070 appendCurrentChar(); 5071 } 5072 else 5073 { 5074 appendCurrentChar(); 5075 } 5076 5077 // if a declaration follows a definition, space pad 5078 if (isLegalNameChar(peekNextChar())) 5079 appendSpaceAfter(); 5080 5081 if (shouldBreakBlocks 5082 && currentHeader != nullptr 5083 && !isHeaderInMultiStatementLine 5084 && parenStack->back() == 0) 5085 { 5086 if (currentHeader == &AS_CASE || currentHeader == &AS_DEFAULT) 5087 { 5088 // do not yet insert a line if "break" statement is outside the braces 5089 string nextText = peekNextText(currentLine.substr(charNum + 1)); 5090 if (nextText.length() > 0 5091 && nextText.substr(0, 5) != "break") 5092 isAppendPostBlockEmptyLineRequested = true; 5093 } 5094 else 5095 isAppendPostBlockEmptyLineRequested = true; 5096 } 5097 } 5098 5099 /** 5100 * format array braces as attached or broken 5101 * determine if the braces can have an inStatement indent 5102 * currentChar contains the brace 5103 * the braces will be appended to the current formattedLine or a new formattedLine as necessary 5104 * the calling function should have a continue statement after calling this method 5105 * 5106 * @param braceType the type of brace to be formatted, must be an ARRAY_TYPE. 5107 * @param isOpeningArrayBrace indicates if this is the opening brace for the array block. 5108 */ 5109 void ASFormatter::formatArrayBraces(BraceType braceType, bool isOpeningArrayBrace) 5110 { 5111 assert(isBraceType(braceType, ARRAY_TYPE)); 5112 assert(currentChar == '{' || currentChar == '}'); 5113 5114 if (currentChar == '{') 5115 { 5116 // is this the first opening brace in the array? 5117 if (isOpeningArrayBrace) 5118 { 5119 if (braceFormatMode == ATTACH_MODE 5120 || braceFormatMode == LINUX_MODE) 5121 { 5122 // break an enum if mozilla 5123 if (isBraceType(braceType, ENUM_TYPE) 5124 && formattingStyle == STYLE_MOZILLA) 5125 { 5126 isInLineBreak = true; 5127 appendCurrentChar(); // don't attach 5128 } 5129 // don't attach to a preprocessor directive or '\' line 5130 else if ((isImmediatelyPostPreprocessor 5131 || (formattedLine.length() > 0 5132 && formattedLine[formattedLine.length() - 1] == '\\')) 5133 && currentLineBeginsWithBrace) 5134 { 5135 isInLineBreak = true; 5136 appendCurrentChar(); // don't attach 5137 } 5138 else if (isCharImmediatelyPostComment) 5139 { 5140 // TODO: attach brace to line-end comment 5141 appendCurrentChar(); // don't attach 5142 } 5143 else if (isCharImmediatelyPostLineComment && !isBraceType(braceType, SINGLE_LINE_TYPE)) 5144 { 5145 appendCharInsideComments(); 5146 } 5147 else 5148 { 5149 // if a blank line precedes this don't attach 5150 if (isEmptyLine(formattedLine)) 5151 appendCurrentChar(); // don't attach 5152 else 5153 { 5154 // if brace is broken or not an assignment 5155 if (currentLineBeginsWithBrace 5156 && !isBraceType(braceType, SINGLE_LINE_TYPE)) 5157 { 5158 appendSpacePad(); 5159 appendCurrentChar(false); // OK to attach 5160 // TODO: debug the following line 5161 testForTimeToSplitFormattedLine(); // line length will have changed 5162 5163 if (currentLineBeginsWithBrace 5164 && currentLineFirstBraceNum == (size_t) charNum) 5165 shouldBreakLineAtNextChar = true; 5166 } 5167 else 5168 { 5169 if (previousNonWSChar != '(') 5170 { 5171 // don't space pad C++11 uniform initialization 5172 if (!isBraceType(braceType, INIT_TYPE)) 5173 appendSpacePad(); 5174 } 5175 appendCurrentChar(); 5176 } 5177 } 5178 } 5179 } 5180 else if (braceFormatMode == BREAK_MODE) 5181 { 5182 if (isWhiteSpace(peekNextChar()) && !isInVirginLine) 5183 breakLine(); 5184 else if (isBeforeAnyComment() && sourceIterator->hasMoreLines()) 5185 { 5186 // do not break unless comment is at line end 5187 if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace) 5188 { 5189 currentChar = ' '; // remove brace from current line 5190 appendOpeningBrace = true; // append brace to following line 5191 } 5192 } 5193 if (!isInLineBreak && previousNonWSChar != '(') 5194 { 5195 // don't space pad C++11 uniform initialization 5196 if (!isBraceType(braceType, INIT_TYPE)) 5197 appendSpacePad(); 5198 } 5199 appendCurrentChar(); 5200 5201 if (currentLineBeginsWithBrace 5202 && currentLineFirstBraceNum == (size_t) charNum 5203 && !isBraceType(braceType, SINGLE_LINE_TYPE)) 5204 shouldBreakLineAtNextChar = true; 5205 } 5206 else if (braceFormatMode == RUN_IN_MODE) 5207 { 5208 if (isWhiteSpace(peekNextChar()) && !isInVirginLine) 5209 breakLine(); 5210 else if (isBeforeAnyComment() && sourceIterator->hasMoreLines()) 5211 { 5212 // do not break unless comment is at line end 5213 if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace) 5214 { 5215 currentChar = ' '; // remove brace from current line 5216 appendOpeningBrace = true; // append brace to following line 5217 } 5218 } 5219 if (!isInLineBreak && previousNonWSChar != '(') 5220 { 5221 // don't space pad C++11 uniform initialization 5222 if (!isBraceType(braceType, INIT_TYPE)) 5223 appendSpacePad(); 5224 } 5225 appendCurrentChar(); 5226 } 5227 else if (braceFormatMode == NONE_MODE) 5228 { 5229 if (currentLineBeginsWithBrace 5230 && (size_t) charNum == currentLineFirstBraceNum) 5231 { 5232 appendCurrentChar(); // don't attach 5233 } 5234 else 5235 { 5236 if (previousNonWSChar != '(') 5237 { 5238 // don't space pad C++11 uniform initialization 5239 if (!isBraceType(braceType, INIT_TYPE)) 5240 appendSpacePad(); 5241 } 5242 appendCurrentChar(false); // OK to attach 5243 } 5244 } 5245 } 5246 else // not the first opening brace 5247 { 5248 if (braceFormatMode == RUN_IN_MODE) 5249 { 5250 if (previousNonWSChar == '{' 5251 && braceTypeStack->size() > 2 5252 && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2], 5253 SINGLE_LINE_TYPE)) 5254 formatArrayRunIn(); 5255 } 5256 else if (!isInLineBreak 5257 && !isWhiteSpace(peekNextChar()) 5258 && previousNonWSChar == '{' 5259 && braceTypeStack->size() > 2 5260 && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2], 5261 SINGLE_LINE_TYPE)) 5262 formatArrayRunIn(); 5263 5264 appendCurrentChar(); 5265 } 5266 } 5267 else if (currentChar == '}') 5268 { 5269 if (attachClosingBraceMode) 5270 { 5271 if (isEmptyLine(formattedLine) // if a blank line precedes this 5272 || isImmediatelyPostPreprocessor 5273 || isCharImmediatelyPostLineComment 5274 || isCharImmediatelyPostComment) 5275 appendCurrentChar(); // don't attach 5276 else 5277 { 5278 appendSpacePad(); 5279 appendCurrentChar(false); // attach 5280 } 5281 } 5282 else 5283 { 5284 // does this close the first opening brace in the array? 5285 // must check if the block is still a single line because of anonymous statements 5286 if (!isBraceType(braceType, INIT_TYPE) 5287 && (!isBraceType(braceType, SINGLE_LINE_TYPE) 5288 || formattedLine.find('{') == string::npos)) 5289 breakLine(); 5290 appendCurrentChar(); 5291 } 5292 5293 // if a declaration follows an enum definition, space pad 5294 char peekedChar = peekNextChar(); 5295 if ((isLegalNameChar(peekedChar) && peekedChar != '.') 5296 || peekedChar == '[') 5297 appendSpaceAfter(); 5298 } 5299 } 5300 5301 /** 5302 * determine if a run-in can be attached. 5303 * if it can insert the indents in formattedLine and reset the current line break. 5304 */ 5305 void ASFormatter::formatRunIn() 5306 { 5307 assert(braceFormatMode == RUN_IN_MODE || braceFormatMode == NONE_MODE); 5308 5309 // keep one line blocks returns true without indenting the run-in 5310 if (formattingStyle != STYLE_PICO 5311 && !isOkToBreakBlock(braceTypeStack->back())) 5312 return; // true; 5313 5314 // make sure the line begins with a brace 5315 size_t lastText = formattedLine.find_last_not_of(" \t"); 5316 if (lastText == string::npos || formattedLine[lastText] != '{') 5317 return; // false; 5318 5319 // make sure the brace is broken 5320 if (formattedLine.find_first_not_of(" \t{") != string::npos) 5321 return; // false; 5322 5323 if (isBraceType(braceTypeStack->back(), NAMESPACE_TYPE)) 5324 return; // false; 5325 5326 bool extraIndent = false; 5327 bool extraHalfIndent = false; 5328 isInLineBreak = true; 5329 5330 // cannot attach a class modifier without indent-classes 5331 if (isCStyle() 5332 && isCharPotentialHeader(currentLine, charNum) 5333 && (isBraceType(braceTypeStack->back(), CLASS_TYPE) 5334 || (isBraceType(braceTypeStack->back(), STRUCT_TYPE) 5335 && isInIndentableStruct))) 5336 { 5337 if (findKeyword(currentLine, charNum, AS_PUBLIC) 5338 || findKeyword(currentLine, charNum, AS_PRIVATE) 5339 || findKeyword(currentLine, charNum, AS_PROTECTED)) 5340 { 5341 if (getModifierIndent()) 5342 extraHalfIndent = true; 5343 else if (!getClassIndent()) 5344 return; // false; 5345 } 5346 else if (getClassIndent()) 5347 extraIndent = true; 5348 } 5349 5350 // cannot attach a 'case' statement without indent-switches 5351 if (!getSwitchIndent() 5352 && isCharPotentialHeader(currentLine, charNum) 5353 && (findKeyword(currentLine, charNum, AS_CASE) 5354 || findKeyword(currentLine, charNum, AS_DEFAULT))) 5355 return; // false; 5356 5357 // extra indent for switch statements 5358 if (getSwitchIndent() 5359 && !preBraceHeaderStack->empty() 5360 && preBraceHeaderStack->back() == &AS_SWITCH 5361 && ((isLegalNameChar(currentChar) 5362 && !findKeyword(currentLine, charNum, AS_CASE)))) 5363 extraIndent = true; 5364 5365 isInLineBreak = false; 5366 // remove for extra whitespace 5367 if (formattedLine.length() > lastText + 1 5368 && formattedLine.find_first_not_of(" \t", lastText + 1) == string::npos) 5369 formattedLine.erase(lastText + 1); 5370 5371 if (extraHalfIndent) 5372 { 5373 int indentLength_ = getIndentLength(); 5374 runInIndentChars = indentLength_ / 2; 5375 formattedLine.append(runInIndentChars - 1, ' '); 5376 } 5377 else if (getForceTabIndentation() && getIndentLength() != getTabLength()) 5378 { 5379 // insert the space indents 5380 string indent; 5381 int indentLength_ = getIndentLength(); 5382 int tabLength_ = getTabLength(); 5383 indent.append(indentLength_, ' '); 5384 if (extraIndent) 5385 indent.append(indentLength_, ' '); 5386 // replace spaces indents with tab indents 5387 size_t tabCount = indent.length() / tabLength_; // truncate extra spaces 5388 indent.replace(0U, tabCount * tabLength_, tabCount, '\t'); 5389 runInIndentChars = indentLength_; 5390 if (indent[0] == ' ') // allow for brace 5391 indent.erase(0, 1); 5392 formattedLine.append(indent); 5393 } 5394 else if (getIndentString() == "\t") 5395 { 5396 appendChar('\t', false); 5397 runInIndentChars = 2; // one for { and one for tab 5398 if (extraIndent) 5399 { 5400 appendChar('\t', false); 5401 runInIndentChars++; 5402 } 5403 } 5404 else // spaces 5405 { 5406 int indentLength_ = getIndentLength(); 5407 formattedLine.append(indentLength_ - 1, ' '); 5408 runInIndentChars = indentLength_; 5409 if (extraIndent) 5410 { 5411 formattedLine.append(indentLength_, ' '); 5412 runInIndentChars += indentLength_; 5413 } 5414 } 5415 isInBraceRunIn = true; 5416 } 5417 5418 /** 5419 * remove whitespace and add indentation for an array run-in. 5420 */ 5421 void ASFormatter::formatArrayRunIn() 5422 { 5423 assert(isBraceType(braceTypeStack->back(), ARRAY_TYPE)); 5424 5425 // make sure the brace is broken 5426 if (formattedLine.find_first_not_of(" \t{") != string::npos) 5427 return; 5428 5429 size_t lastText = formattedLine.find_last_not_of(" \t"); 5430 if (lastText == string::npos || formattedLine[lastText] != '{') 5431 return; 5432 5433 // check for extra whitespace 5434 if (formattedLine.length() > lastText + 1 5435 && formattedLine.find_first_not_of(" \t", lastText + 1) == string::npos) 5436 formattedLine.erase(lastText + 1); 5437 5438 if (getIndentString() == "\t") 5439 { 5440 appendChar('\t', false); 5441 runInIndentChars = 2; // one for { and one for tab 5442 } 5443 else 5444 { 5445 int indent = getIndentLength(); 5446 formattedLine.append(indent - 1, ' '); 5447 runInIndentChars = indent; 5448 } 5449 isInBraceRunIn = true; 5450 isInLineBreak = false; 5451 } 5452 5453 /** 5454 * delete a braceTypeStack vector object 5455 * BraceTypeStack did not work with the DeleteContainer template 5456 */ 5457 void ASFormatter::deleteContainer(vector<BraceType>*& container) 5458 { 5459 if (container != nullptr) 5460 { 5461 container->clear(); 5462 delete (container); 5463 container = nullptr; 5464 } 5465 } 5466 5467 /** 5468 * delete a vector object 5469 * T is the type of vector 5470 * used for all vectors except braceTypeStack 5471 */ 5472 template<typename T> 5473 void ASFormatter::deleteContainer(T& container) 5474 { 5475 if (container != nullptr) 5476 { 5477 container->clear(); 5478 delete (container); 5479 container = nullptr; 5480 } 5481 } 5482 5483 /** 5484 * initialize a braceType vector object 5485 * braceType did not work with the DeleteContainer template 5486 */ 5487 void ASFormatter::initContainer(vector<BraceType>*& container, vector<BraceType>* value) 5488 { 5489 if (container != nullptr) 5490 deleteContainer(container); 5491 container = value; 5492 } 5493 5494 /** 5495 * initialize a vector object 5496 * T is the type of vector 5497 * used for all vectors except braceTypeStack 5498 */ 5499 template<typename T> 5500 void ASFormatter::initContainer(T& container, T value) 5501 { 5502 // since the ASFormatter object is never deleted, 5503 // the existing vectors must be deleted before creating new ones 5504 if (container != nullptr) 5505 deleteContainer(container); 5506 container = value; 5507 } 5508 5509 /** 5510 * convert a tab to spaces. 5511 * charNum points to the current character to convert to spaces. 5512 * tabIncrementIn is the increment that must be added for tab indent characters 5513 * to get the correct column for the current tab. 5514 * replaces the tab in currentLine with the required number of spaces. 5515 * replaces the value of currentChar. 5516 */ 5517 void ASFormatter::convertTabToSpaces() 5518 { 5519 assert(currentChar == '\t'); 5520 5521 // do NOT replace if in quotes 5522 if (isInQuote || isInQuoteContinuation) 5523 return; 5524 5525 size_t tabSize = getTabLength(); 5526 size_t numSpaces = tabSize - ((tabIncrementIn + charNum) % tabSize); 5527 currentLine.replace(charNum, 1, numSpaces, ' '); 5528 currentChar = currentLine[charNum]; 5529 } 5530 5531 /** 5532 * is it ok to break this block? 5533 */ 5534 bool ASFormatter::isOkToBreakBlock(BraceType braceType) const 5535 { 5536 // Actually, there should not be an ARRAY_TYPE brace here. 5537 // But this will avoid breaking a one line block when there is. 5538 // Otherwise they will be formatted differently on consecutive runs. 5539 if (isBraceType(braceType, ARRAY_TYPE) 5540 && isBraceType(braceType, SINGLE_LINE_TYPE)) 5541 return false; 5542 if (isBraceType(braceType, COMMAND_TYPE) 5543 && isBraceType(braceType, EMPTY_BLOCK_TYPE)) 5544 return false; 5545 if (!isBraceType(braceType, SINGLE_LINE_TYPE) 5546 || isBraceType(braceType, BREAK_BLOCK_TYPE) 5547 || shouldBreakOneLineBlocks) 5548 return true; 5549 return false; 5550 } 5551 5552 /** 5553 * check if a sharp header is a paren or non-paren header 5554 */ 5555 bool ASFormatter::isSharpStyleWithParen(const string* header) const 5556 { 5557 return (isSharpStyle() && peekNextChar() == '(' 5558 && (header == &AS_CATCH 5559 || header == &AS_DELEGATE)); 5560 } 5561 5562 /** 5563 * Check for a following header when a comment is reached. 5564 * firstLine must contain the start of the comment. 5565 * return value is a pointer to the header or nullptr. 5566 */ 5567 const string* ASFormatter::checkForHeaderFollowingComment(const string& firstLine) const 5568 { 5569 assert(isInComment || isInLineComment); 5570 assert(shouldBreakElseIfs || shouldBreakBlocks || isInSwitchStatement()); 5571 // look ahead to find the next non-comment text 5572 bool endOnEmptyLine = (currentHeader == nullptr); 5573 if (isInSwitchStatement()) 5574 endOnEmptyLine = false; 5575 string nextText = peekNextText(firstLine, endOnEmptyLine); 5576 5577 if (nextText.length() == 0 || !isCharPotentialHeader(nextText, 0)) 5578 return nullptr; 5579 5580 return ASBase::findHeader(nextText, 0, headers); 5581 } 5582 5583 /** 5584 * process preprocessor statements. 5585 * charNum should be the index of the #. 5586 * 5587 * delete braceTypeStack entries added by #if if a #else is found. 5588 * prevents double entries in the braceTypeStack. 5589 */ 5590 void ASFormatter::processPreprocessor() 5591 { 5592 assert(currentChar == '#'); 5593 5594 const size_t preproc = currentLine.find_first_not_of(" \t", charNum + 1); 5595 5596 if (preproc == string::npos) 5597 return; 5598 5599 if (currentLine.compare(preproc, 2, "if") == 0) 5600 { 5601 preprocBraceTypeStackSize = braceTypeStack->size(); 5602 } 5603 else if (currentLine.compare(preproc, 4, "else") == 0) 5604 { 5605 // delete stack entries added in #if 5606 // should be replaced by #else 5607 if (preprocBraceTypeStackSize > 0) 5608 { 5609 int addedPreproc = braceTypeStack->size() - preprocBraceTypeStackSize; 5610 for (int i = 0; i < addedPreproc; i++) 5611 braceTypeStack->pop_back(); 5612 } 5613 } 5614 } 5615 5616 /** 5617 * determine if the next line starts a comment 5618 * and a header follows the comment or comments. 5619 */ 5620 bool ASFormatter::commentAndHeaderFollows() 5621 { 5622 // called ONLY IF shouldDeleteEmptyLines and shouldBreakBlocks are TRUE. 5623 assert(shouldDeleteEmptyLines && shouldBreakBlocks); 5624 5625 // is the next line a comment 5626 auto stream = make_shared<ASPeekStream>(sourceIterator); 5627 if (!stream->hasMoreLines()) 5628 return false; 5629 string nextLine_ = stream->peekNextLine(); 5630 size_t firstChar = nextLine_.find_first_not_of(" \t"); 5631 if (firstChar == string::npos 5632 || !(nextLine_.compare(firstChar, 2, "//") == 0 5633 || nextLine_.compare(firstChar, 2, "/*") == 0)) 5634 return false; 5635 5636 // find the next non-comment text, and reset 5637 string nextText = peekNextText(nextLine_, false, stream); 5638 if (nextText.length() == 0 || !isCharPotentialHeader(nextText, 0)) 5639 return false; 5640 5641 const string* newHeader = ASBase::findHeader(nextText, 0, headers); 5642 5643 if (newHeader == nullptr) 5644 return false; 5645 5646 // if a closing header, reset break unless break is requested 5647 if (isClosingHeader(newHeader) && !shouldBreakClosingHeaderBlocks) 5648 { 5649 isAppendPostBlockEmptyLineRequested = false; 5650 return false; 5651 } 5652 5653 return true; 5654 } 5655 5656 /** 5657 * determine if a brace should be attached or broken 5658 * uses braces in the braceTypeStack 5659 * the last brace in the braceTypeStack is the one being formatted 5660 * returns true if the brace should be broken 5661 */ 5662 bool ASFormatter::isCurrentBraceBroken() const 5663 { 5664 assert(braceTypeStack->size() > 1); 5665 5666 bool breakBrace = false; 5667 size_t stackEnd = braceTypeStack->size() - 1; 5668 5669 // check brace modifiers 5670 if (shouldAttachExternC 5671 && isBraceType((*braceTypeStack)[stackEnd], EXTERN_TYPE)) 5672 { 5673 return false; 5674 } 5675 if (shouldAttachNamespace 5676 && isBraceType((*braceTypeStack)[stackEnd], NAMESPACE_TYPE)) 5677 { 5678 return false; 5679 } 5680 if (shouldAttachClass 5681 && (isBraceType((*braceTypeStack)[stackEnd], CLASS_TYPE) 5682 || isBraceType((*braceTypeStack)[stackEnd], INTERFACE_TYPE))) 5683 { 5684 return false; 5685 } 5686 if (shouldAttachInline 5687 && isCStyle() // for C++ only 5688 && braceFormatMode != RUN_IN_MODE 5689 && !(currentLineBeginsWithBrace && peekNextChar() == '/') 5690 && isBraceType((*braceTypeStack)[stackEnd], COMMAND_TYPE)) 5691 { 5692 size_t i; 5693 for (i = 1; i < braceTypeStack->size(); i++) 5694 if (isBraceType((*braceTypeStack)[i], CLASS_TYPE) 5695 || isBraceType((*braceTypeStack)[i], STRUCT_TYPE)) 5696 return false; 5697 } 5698 5699 // check braces 5700 if (isBraceType((*braceTypeStack)[stackEnd], EXTERN_TYPE)) 5701 { 5702 if (currentLineBeginsWithBrace 5703 || braceFormatMode == RUN_IN_MODE) 5704 breakBrace = true; 5705 } 5706 else if (braceFormatMode == NONE_MODE) 5707 { 5708 if (currentLineBeginsWithBrace 5709 && currentLineFirstBraceNum == (size_t) charNum) 5710 breakBrace = true; 5711 } 5712 else if (braceFormatMode == BREAK_MODE || braceFormatMode == RUN_IN_MODE) 5713 { 5714 breakBrace = true; 5715 } 5716 else if (braceFormatMode == LINUX_MODE) 5717 { 5718 // break a namespace if NOT stroustrup or mozilla 5719 if (isBraceType((*braceTypeStack)[stackEnd], NAMESPACE_TYPE)) 5720 { 5721 if (formattingStyle != STYLE_STROUSTRUP 5722 && formattingStyle != STYLE_MOZILLA) 5723 breakBrace = true; 5724 } 5725 // break a class or interface if NOT stroustrup 5726 else if (isBraceType((*braceTypeStack)[stackEnd], CLASS_TYPE) 5727 || isBraceType((*braceTypeStack)[stackEnd], INTERFACE_TYPE)) 5728 { 5729 if (formattingStyle != STYLE_STROUSTRUP) 5730 breakBrace = true; 5731 } 5732 // break a struct if mozilla - an enum is processed as an array brace 5733 else if (isBraceType((*braceTypeStack)[stackEnd], STRUCT_TYPE)) 5734 { 5735 if (formattingStyle == STYLE_MOZILLA) 5736 breakBrace = true; 5737 } 5738 // break the first brace if a function 5739 else if (isBraceType((*braceTypeStack)[stackEnd], COMMAND_TYPE)) 5740 { 5741 if (stackEnd == 1) 5742 { 5743 breakBrace = true; 5744 } 5745 else if (stackEnd > 1) 5746 { 5747 // break the first brace after these if a function 5748 if (isBraceType((*braceTypeStack)[stackEnd - 1], NAMESPACE_TYPE) 5749 || isBraceType((*braceTypeStack)[stackEnd - 1], CLASS_TYPE) 5750 || isBraceType((*braceTypeStack)[stackEnd - 1], ARRAY_TYPE) 5751 || isBraceType((*braceTypeStack)[stackEnd - 1], STRUCT_TYPE) 5752 || isBraceType((*braceTypeStack)[stackEnd - 1], EXTERN_TYPE)) 5753 { 5754 breakBrace = true; 5755 } 5756 } 5757 } 5758 } 5759 return breakBrace; 5760 } 5761 5762 /** 5763 * format comment body 5764 * the calling function should have a continue statement after calling this method 5765 */ 5766 void ASFormatter::formatCommentBody() 5767 { 5768 assert(isInComment); 5769 5770 // append the comment 5771 while (charNum < (int) currentLine.length()) 5772 { 5773 currentChar = currentLine[charNum]; 5774 if (isSequenceReached("*/")) 5775 { 5776 formatCommentCloser(); 5777 break; 5778 } 5779 if (currentChar == '\t' && shouldConvertTabs) 5780 convertTabToSpaces(); 5781 appendCurrentChar(); 5782 ++charNum; 5783 } 5784 if (shouldStripCommentPrefix) 5785 stripCommentPrefix(); 5786 } 5787 5788 /** 5789 * format a comment opener 5790 * the comment opener will be appended to the current formattedLine or a new formattedLine as necessary 5791 * the calling function should have a continue statement after calling this method 5792 */ 5793 void ASFormatter::formatCommentOpener() 5794 { 5795 assert(isSequenceReached("/*")); 5796 5797 isInComment = isInCommentStartLine = true; 5798 isImmediatelyPostLineComment = false; 5799 if (previousNonWSChar == '}') 5800 resetEndOfStatement(); 5801 5802 // Check for a following header. 5803 // For speed do not check multiple comment lines more than once. 5804 // For speed do not check shouldBreakBlocks if previous line is empty, a comment, or a '{'. 5805 const string* followingHeader = nullptr; 5806 if ((doesLineStartComment 5807 && !isImmediatelyPostCommentOnly 5808 && isBraceType(braceTypeStack->back(), COMMAND_TYPE)) 5809 && (shouldBreakElseIfs 5810 || isInSwitchStatement() 5811 || (shouldBreakBlocks 5812 && !isImmediatelyPostEmptyLine 5813 && previousCommandChar != '{'))) 5814 followingHeader = checkForHeaderFollowingComment(currentLine.substr(charNum)); 5815 5816 if (spacePadNum != 0 && !isInLineBreak) 5817 adjustComments(); 5818 formattedLineCommentNum = formattedLine.length(); 5819 5820 // must be done BEFORE appendSequence 5821 if (previousCommandChar == '{' 5822 && !isImmediatelyPostComment 5823 && !isImmediatelyPostLineComment) 5824 { 5825 if (isBraceType(braceTypeStack->back(), NAMESPACE_TYPE)) 5826 { 5827 // namespace run-in is always broken. 5828 isInLineBreak = true; 5829 } 5830 else if (braceFormatMode == NONE_MODE) 5831 { 5832 // should a run-in statement be attached? 5833 if (currentLineBeginsWithBrace) 5834 formatRunIn(); 5835 } 5836 else if (braceFormatMode == ATTACH_MODE) 5837 { 5838 // if the brace was not attached? 5839 if (formattedLine.length() > 0 && formattedLine[0] == '{' 5840 && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)) 5841 isInLineBreak = true; 5842 } 5843 else if (braceFormatMode == RUN_IN_MODE) 5844 { 5845 // should a run-in statement be attached? 5846 if (formattedLine.length() > 0 && formattedLine[0] == '{') 5847 formatRunIn(); 5848 } 5849 } 5850 else if (!doesLineStartComment) 5851 noTrimCommentContinuation = true; 5852 5853 // ASBeautifier needs to know the following statements 5854 if (shouldBreakElseIfs && followingHeader == &AS_ELSE) 5855 elseHeaderFollowsComments = true; 5856 if (followingHeader == &AS_CASE || followingHeader == &AS_DEFAULT) 5857 caseHeaderFollowsComments = true; 5858 5859 // appendSequence will write the previous line 5860 appendSequence(AS_OPEN_COMMENT); 5861 goForward(1); 5862 5863 // must be done AFTER appendSequence 5864 5865 // Break before the comment if a header follows the line comment. 5866 // But not break if previous line is empty, a comment, or a '{'. 5867 if (shouldBreakBlocks 5868 && followingHeader != nullptr 5869 && !isImmediatelyPostEmptyLine 5870 && previousCommandChar != '{') 5871 { 5872 if (isClosingHeader(followingHeader)) 5873 { 5874 if (!shouldBreakClosingHeaderBlocks) 5875 isPrependPostBlockEmptyLineRequested = false; 5876 } 5877 // if an opening header, break before the comment 5878 else 5879 isPrependPostBlockEmptyLineRequested = true; 5880 } 5881 5882 if (previousCommandChar == '}') 5883 currentHeader = nullptr; 5884 } 5885 5886 /** 5887 * format a comment closer 5888 * the comment closer will be appended to the current formattedLine 5889 */ 5890 void ASFormatter::formatCommentCloser() 5891 { 5892 assert(isSequenceReached("*/")); 5893 isInComment = false; 5894 noTrimCommentContinuation = false; 5895 isImmediatelyPostComment = true; 5896 appendSequence(AS_CLOSE_COMMENT); 5897 goForward(1); 5898 if (doesLineStartComment 5899 && (currentLine.find_first_not_of(" \t", charNum + 1) == string::npos)) 5900 lineEndsInCommentOnly = true; 5901 if (peekNextChar() == '}' 5902 && previousCommandChar != ';' 5903 && !isBraceType(braceTypeStack->back(), ARRAY_TYPE) 5904 && !isInPreprocessor 5905 && isOkToBreakBlock(braceTypeStack->back())) 5906 { 5907 isInLineBreak = true; 5908 shouldBreakLineAtNextChar = true; 5909 } 5910 } 5911 5912 /** 5913 * format a line comment body 5914 * the calling function should have a continue statement after calling this method 5915 */ 5916 void ASFormatter::formatLineCommentBody() 5917 { 5918 assert(isInLineComment); 5919 5920 // append the comment 5921 while (charNum < (int) currentLine.length()) 5922 // && !isLineReady // commented out in release 2.04, unnecessary 5923 { 5924 currentChar = currentLine[charNum]; 5925 if (currentChar == '\t' && shouldConvertTabs) 5926 convertTabToSpaces(); 5927 appendCurrentChar(); 5928 ++charNum; 5929 } 5930 5931 // explicitly break a line when a line comment's end is found. 5932 if (charNum == (int) currentLine.length()) 5933 { 5934 isInLineBreak = true; 5935 isInLineComment = false; 5936 isImmediatelyPostLineComment = true; 5937 currentChar = 0; //make sure it is a neutral char. 5938 } 5939 } 5940 5941 /** 5942 * format a line comment opener 5943 * the line comment opener will be appended to the current formattedLine or a new formattedLine as necessary 5944 * the calling function should have a continue statement after calling this method 5945 */ 5946 void ASFormatter::formatLineCommentOpener() 5947 { 5948 assert(isSequenceReached("//")); 5949 5950 if ((int) currentLine.length() > charNum + 2 5951 && currentLine[charNum + 2] == '\xf2') // check for windows line marker 5952 isAppendPostBlockEmptyLineRequested = false; 5953 5954 isInLineComment = true; 5955 isCharImmediatelyPostComment = false; 5956 if (previousNonWSChar == '}') 5957 resetEndOfStatement(); 5958 5959 // Check for a following header. 5960 // For speed do not check multiple comment lines more than once. 5961 // For speed do not check shouldBreakBlocks if previous line is empty, a comment, or a '{'. 5962 const string* followingHeader = nullptr; 5963 if ((lineIsLineCommentOnly 5964 && !isImmediatelyPostCommentOnly 5965 && isBraceType(braceTypeStack->back(), COMMAND_TYPE)) 5966 && (shouldBreakElseIfs 5967 || isInSwitchStatement() 5968 || (shouldBreakBlocks 5969 && !isImmediatelyPostEmptyLine 5970 && previousCommandChar != '{'))) 5971 followingHeader = checkForHeaderFollowingComment(currentLine.substr(charNum)); 5972 5973 // do not indent if in column 1 or 2 5974 // or in a namespace before the opening brace 5975 if ((!shouldIndentCol1Comments && !lineCommentNoIndent) 5976 || foundNamespaceHeader) 5977 { 5978 if (charNum == 0) 5979 lineCommentNoIndent = true; 5980 else if (charNum == 1 && currentLine[0] == ' ') 5981 lineCommentNoIndent = true; 5982 } 5983 // move comment if spaces were added or deleted 5984 if (!lineCommentNoIndent && spacePadNum != 0 && !isInLineBreak) 5985 adjustComments(); 5986 formattedLineCommentNum = formattedLine.length(); 5987 5988 // must be done BEFORE appendSequence 5989 // check for run-in statement 5990 if (previousCommandChar == '{' 5991 && !isImmediatelyPostComment 5992 && !isImmediatelyPostLineComment) 5993 { 5994 if (braceFormatMode == NONE_MODE) 5995 { 5996 if (currentLineBeginsWithBrace) 5997 formatRunIn(); 5998 } 5999 else if (braceFormatMode == RUN_IN_MODE) 6000 { 6001 if (!lineCommentNoIndent) 6002 formatRunIn(); 6003 else 6004 isInLineBreak = true; 6005 } 6006 else if (braceFormatMode == BREAK_MODE) 6007 { 6008 if (formattedLine.length() > 0 && formattedLine[0] == '{') 6009 isInLineBreak = true; 6010 } 6011 else 6012 { 6013 if (currentLineBeginsWithBrace) 6014 isInLineBreak = true; 6015 } 6016 } 6017 6018 // ASBeautifier needs to know the following statements 6019 if (shouldBreakElseIfs && followingHeader == &AS_ELSE) 6020 elseHeaderFollowsComments = true; 6021 if (followingHeader == &AS_CASE || followingHeader == &AS_DEFAULT) 6022 caseHeaderFollowsComments = true; 6023 6024 // appendSequence will write the previous line 6025 appendSequence(AS_OPEN_LINE_COMMENT); 6026 goForward(1); 6027 6028 // must be done AFTER appendSequence 6029 6030 // Break before the comment if a header follows the line comment. 6031 // But do not break if previous line is empty, a comment, or a '{'. 6032 if (shouldBreakBlocks 6033 && followingHeader != nullptr 6034 && !isImmediatelyPostEmptyLine 6035 && previousCommandChar != '{') 6036 { 6037 if (isClosingHeader(followingHeader)) 6038 { 6039 if (!shouldBreakClosingHeaderBlocks) 6040 isPrependPostBlockEmptyLineRequested = false; 6041 } 6042 // if an opening header, break before the comment 6043 else 6044 isPrependPostBlockEmptyLineRequested = true; 6045 } 6046 6047 if (previousCommandChar == '}') 6048 currentHeader = nullptr; 6049 6050 // if tabbed input don't convert the immediately following tabs to spaces 6051 if (getIndentString() == "\t" && lineCommentNoIndent) 6052 { 6053 while (charNum + 1 < (int) currentLine.length() 6054 && currentLine[charNum + 1] == '\t') 6055 { 6056 currentChar = currentLine[++charNum]; 6057 appendCurrentChar(); 6058 } 6059 } 6060 6061 // explicitly break a line when a line comment's end is found. 6062 if (charNum + 1 == (int) currentLine.length()) 6063 { 6064 isInLineBreak = true; 6065 isInLineComment = false; 6066 isImmediatelyPostLineComment = true; 6067 currentChar = 0; //make sure it is a neutral char. 6068 } 6069 } 6070 6071 /** 6072 * format quote body 6073 * the calling function should have a continue statement after calling this method 6074 */ 6075 void ASFormatter::formatQuoteBody() 6076 { 6077 assert(isInQuote); 6078 6079 if (isSpecialChar) 6080 { 6081 isSpecialChar = false; 6082 } 6083 else if (currentChar == '\\' && !isInVerbatimQuote) 6084 { 6085 if (peekNextChar() == ' ') // is this '\' at end of line 6086 haveLineContinuationChar = true; 6087 else 6088 isSpecialChar = true; 6089 } 6090 else if (isInVerbatimQuote && currentChar == '"') 6091 { 6092 if (isCStyle()) 6093 { 6094 string delim = ')' + verbatimDelimiter; 6095 int delimStart = charNum - delim.length(); 6096 if (delimStart > 0 && currentLine.substr(delimStart, delim.length()) == delim) 6097 { 6098 isInQuote = false; 6099 isInVerbatimQuote = false; 6100 } 6101 } 6102 else if (isSharpStyle()) 6103 { 6104 if ((int) currentLine.length() > charNum + 1 6105 && currentLine[charNum + 1] == '"') // check consecutive quotes 6106 { 6107 appendSequence("\"\""); 6108 goForward(1); 6109 return; 6110 } 6111 isInQuote = false; 6112 isInVerbatimQuote = false; 6113 } 6114 } 6115 else if (quoteChar == currentChar) 6116 { 6117 isInQuote = false; 6118 } 6119 6120 appendCurrentChar(); 6121 6122 // append the text to the ending quoteChar or an escape sequence 6123 // tabs in quotes are NOT changed by convert-tabs 6124 if (isInQuote && currentChar != '\\') 6125 { 6126 while (charNum + 1 < (int) currentLine.length() 6127 && currentLine[charNum + 1] != quoteChar 6128 && currentLine[charNum + 1] != '\\') 6129 { 6130 currentChar = currentLine[++charNum]; 6131 appendCurrentChar(); 6132 } 6133 } 6134 if (charNum + 1 >= (int) currentLine.length() 6135 && currentChar != '\\' 6136 && !isInVerbatimQuote) 6137 isInQuote = false; // missing closing quote 6138 } 6139 6140 /** 6141 * format a quote opener 6142 * the quote opener will be appended to the current formattedLine or a new formattedLine as necessary 6143 * the calling function should have a continue statement after calling this method 6144 */ 6145 void ASFormatter::formatQuoteOpener() 6146 { 6147 assert(currentChar == '"' 6148 || (currentChar == '\'' && !isDigitSeparator(currentLine, charNum))); 6149 6150 isInQuote = true; 6151 quoteChar = currentChar; 6152 if (isCStyle() && previousChar == 'R') 6153 { 6154 int parenPos = currentLine.find('(', charNum); 6155 if (parenPos != -1) 6156 { 6157 isInVerbatimQuote = true; 6158 verbatimDelimiter = currentLine.substr(charNum + 1, parenPos - charNum - 1); 6159 } 6160 } 6161 else if (isSharpStyle() && previousChar == '@') 6162 isInVerbatimQuote = true; 6163 6164 // a quote following a brace is an array 6165 if (previousCommandChar == '{' 6166 && !isImmediatelyPostComment 6167 && !isImmediatelyPostLineComment 6168 && isNonInStatementArray 6169 && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE) 6170 && !isWhiteSpace(peekNextChar())) 6171 { 6172 if (braceFormatMode == NONE_MODE) 6173 { 6174 if (currentLineBeginsWithBrace) 6175 formatRunIn(); 6176 } 6177 else if (braceFormatMode == RUN_IN_MODE) 6178 { 6179 formatRunIn(); 6180 } 6181 else if (braceFormatMode == BREAK_MODE) 6182 { 6183 if (formattedLine.length() > 0 && formattedLine[0] == '{') 6184 isInLineBreak = true; 6185 } 6186 else 6187 { 6188 if (currentLineBeginsWithBrace) 6189 isInLineBreak = true; 6190 } 6191 } 6192 previousCommandChar = ' '; 6193 appendCurrentChar(); 6194 } 6195 6196 /** 6197 * get the next line comment adjustment that results from breaking a closing brace. 6198 * the brace must be on the same line as the closing header. 6199 * i.e "} else" changed to "} <NL> else". 6200 */ 6201 int ASFormatter::getNextLineCommentAdjustment() 6202 { 6203 assert(foundClosingHeader && previousNonWSChar == '}'); 6204 if (charNum < 1) // "else" is in column 1 6205 return 0; 6206 size_t lastBrace = currentLine.rfind('}', charNum - 1); 6207 if (lastBrace != string::npos) 6208 return (lastBrace - charNum); // return a negative number 6209 return 0; 6210 } 6211 6212 // for console build only 6213 LineEndFormat ASFormatter::getLineEndFormat() const 6214 { 6215 return lineEnd; 6216 } 6217 6218 /** 6219 * get the current line comment adjustment that results from attaching 6220 * a closing header to a closing brace. 6221 * the brace must be on the line previous to the closing header. 6222 * the adjustment is 2 chars, one for the brace and one for the space. 6223 * i.e "} <NL> else" changed to "} else". 6224 */ 6225 int ASFormatter::getCurrentLineCommentAdjustment() 6226 { 6227 assert(foundClosingHeader && previousNonWSChar == '}'); 6228 if (charNum < 1) 6229 return 2; 6230 size_t lastBrace = currentLine.rfind('}', charNum - 1); 6231 if (lastBrace == string::npos) 6232 return 2; 6233 return 0; 6234 } 6235 6236 /** 6237 * get the previous word on a line 6238 * the argument 'currPos' must point to the current position. 6239 * 6240 * @return is the previous word or an empty string if none found. 6241 */ 6242 string ASFormatter::getPreviousWord(const string& line, int currPos) const 6243 { 6244 // get the last legal word (may be a number) 6245 if (currPos == 0) 6246 return string(); 6247 6248 size_t end = line.find_last_not_of(" \t", currPos - 1); 6249 if (end == string::npos || !isLegalNameChar(line[end])) 6250 return string(); 6251 6252 int start; // start of the previous word 6253 for (start = end; start > -1; start--) 6254 { 6255 if (!isLegalNameChar(line[start]) || line[start] == '.') 6256 break; 6257 } 6258 start++; 6259 6260 return (line.substr(start, end - start + 1)); 6261 } 6262 6263 /** 6264 * check if a line break is needed when a closing brace 6265 * is followed by a closing header. 6266 * the break depends on the braceFormatMode and other factors. 6267 */ 6268 void ASFormatter::isLineBreakBeforeClosingHeader() 6269 { 6270 assert(foundClosingHeader && previousNonWSChar == '}'); 6271 6272 if (currentHeader == &AS_WHILE && shouldAttachClosingWhile) 6273 { 6274 appendClosingHeader(); 6275 return; 6276 } 6277 6278 if (braceFormatMode == BREAK_MODE 6279 || braceFormatMode == RUN_IN_MODE 6280 || attachClosingBraceMode) 6281 { 6282 isInLineBreak = true; 6283 } 6284 else if (braceFormatMode == NONE_MODE) 6285 { 6286 if (shouldBreakClosingHeaderBraces 6287 || getBraceIndent() || getBlockIndent()) 6288 { 6289 isInLineBreak = true; 6290 } 6291 else 6292 { 6293 appendSpacePad(); 6294 // is closing brace broken? 6295 size_t i = currentLine.find_first_not_of(" \t"); 6296 if (i != string::npos && currentLine[i] == '}') 6297 isInLineBreak = false; 6298 6299 if (shouldBreakBlocks) 6300 isAppendPostBlockEmptyLineRequested = false; 6301 } 6302 } 6303 // braceFormatMode == ATTACH_MODE, LINUX_MODE 6304 else 6305 { 6306 if (shouldBreakClosingHeaderBraces 6307 || getBraceIndent() || getBlockIndent()) 6308 { 6309 isInLineBreak = true; 6310 } 6311 else 6312 { 6313 appendClosingHeader(); 6314 if (shouldBreakBlocks) 6315 isAppendPostBlockEmptyLineRequested = false; 6316 } 6317 } 6318 } 6319 6320 /** 6321 * Append a closing header to the previous closing brace, if possible 6322 */ 6323 void ASFormatter::appendClosingHeader() 6324 { 6325 // if a blank line does not precede this 6326 // or last line is not a one line block, attach header 6327 bool previousLineIsEmpty = isEmptyLine(formattedLine); 6328 int previousLineIsOneLineBlock = 0; 6329 size_t firstBrace = findNextChar(formattedLine, '{'); 6330 if (firstBrace != string::npos) 6331 previousLineIsOneLineBlock = isOneLineBlockReached(formattedLine, firstBrace); 6332 if (!previousLineIsEmpty 6333 && previousLineIsOneLineBlock == 0) 6334 { 6335 isInLineBreak = false; 6336 appendSpacePad(); 6337 spacePadNum = 0; // don't count as comment padding 6338 } 6339 } 6340 6341 /** 6342 * Add braces to a single line statement following a header. 6343 * braces are not added if the proper conditions are not met. 6344 * braces are added to the currentLine. 6345 */ 6346 bool ASFormatter::addBracesToStatement() 6347 { 6348 assert(isImmediatelyPostHeader); 6349 6350 if (currentHeader != &AS_IF 6351 && currentHeader != &AS_ELSE 6352 && currentHeader != &AS_FOR 6353 && currentHeader != &AS_WHILE 6354 && currentHeader != &AS_DO 6355 && currentHeader != &AS_FOREACH 6356 && currentHeader != &AS_QFOREACH 6357 && currentHeader != &AS_QFOREVER 6358 && currentHeader != &AS_FOREVER) 6359 return false; 6360 6361 if (currentHeader == &AS_WHILE && foundClosingHeader) // do-while 6362 return false; 6363 6364 // do not brace an empty statement 6365 if (currentChar == ';') 6366 return false; 6367 6368 // do not add if a header follows 6369 if (isCharPotentialHeader(currentLine, charNum)) 6370 if (findHeader(headers) != nullptr) 6371 return false; 6372 6373 // find the next semi-colon 6374 size_t nextSemiColon = charNum; 6375 if (currentChar != ';') 6376 nextSemiColon = findNextChar(currentLine, ';', charNum + 1); 6377 if (nextSemiColon == string::npos) 6378 return false; 6379 6380 // add closing brace before changing the line length 6381 if (nextSemiColon == currentLine.length() - 1) 6382 currentLine.append(" }"); 6383 else 6384 currentLine.insert(nextSemiColon + 1, " }"); 6385 // add opening brace 6386 currentLine.insert(charNum, "{ "); 6387 assert(computeChecksumIn("{}")); 6388 currentChar = '{'; 6389 if ((int) currentLine.find_first_not_of(" \t") == charNum) 6390 currentLineBeginsWithBrace = true; 6391 // remove extra spaces 6392 if (!shouldAddOneLineBraces) 6393 { 6394 size_t lastText = formattedLine.find_last_not_of(" \t"); 6395 if ((formattedLine.length() - 1) - lastText > 1) 6396 formattedLine.erase(lastText + 1); 6397 } 6398 return true; 6399 } 6400 6401 /** 6402 * Remove braces from a single line statement following a header. 6403 * braces are not removed if the proper conditions are not met. 6404 * The first brace is replaced by a space. 6405 */ 6406 bool ASFormatter::removeBracesFromStatement() 6407 { 6408 assert(isImmediatelyPostHeader); 6409 assert(currentChar == '{'); 6410 6411 if (currentHeader != &AS_IF 6412 && currentHeader != &AS_ELSE 6413 && currentHeader != &AS_FOR 6414 && currentHeader != &AS_WHILE 6415 && currentHeader != &AS_FOREACH) 6416 return false; 6417 6418 if (currentHeader == &AS_WHILE && foundClosingHeader) // do-while 6419 return false; 6420 6421 bool isFirstLine = true; 6422 string nextLine_; 6423 // leave nextLine_ empty if end of line comment follows 6424 if (!isBeforeAnyLineEndComment(charNum) || currentLineBeginsWithBrace) 6425 nextLine_ = currentLine.substr(charNum + 1); 6426 size_t nextChar = 0; 6427 6428 // find the first non-blank text 6429 ASPeekStream stream(sourceIterator); 6430 while (stream.hasMoreLines() || isFirstLine) 6431 { 6432 if (isFirstLine) 6433 isFirstLine = false; 6434 else 6435 { 6436 nextLine_ = stream.peekNextLine(); 6437 nextChar = 0; 6438 } 6439 6440 nextChar = nextLine_.find_first_not_of(" \t", nextChar); 6441 if (nextChar != string::npos) 6442 break; 6443 } 6444 if (!stream.hasMoreLines()) 6445 return false; 6446 6447 // don't remove if comments or a header follow the brace 6448 if ((nextLine_.compare(nextChar, 2, "/*") == 0) 6449 || (nextLine_.compare(nextChar, 2, "//") == 0) 6450 || (isCharPotentialHeader(nextLine_, nextChar) 6451 && ASBase::findHeader(nextLine_, nextChar, headers) != nullptr)) 6452 return false; 6453 6454 // find the next semi-colon 6455 size_t nextSemiColon = nextChar; 6456 if (nextLine_[nextChar] != ';') 6457 nextSemiColon = findNextChar(nextLine_, ';', nextChar + 1); 6458 if (nextSemiColon == string::npos) 6459 return false; 6460 6461 // find the closing brace 6462 isFirstLine = true; 6463 nextChar = nextSemiColon + 1; 6464 while (stream.hasMoreLines() || isFirstLine) 6465 { 6466 if (isFirstLine) 6467 isFirstLine = false; 6468 else 6469 { 6470 nextLine_ = stream.peekNextLine(); 6471 nextChar = 0; 6472 } 6473 nextChar = nextLine_.find_first_not_of(" \t", nextChar); 6474 if (nextChar != string::npos) 6475 break; 6476 } 6477 if (nextLine_.length() == 0 || nextLine_[nextChar] != '}') 6478 return false; 6479 6480 // remove opening brace 6481 currentLine[charNum] = currentChar = ' '; 6482 assert(adjustChecksumIn(-'{')); 6483 return true; 6484 } 6485 6486 /** 6487 * Find the next character that is not in quotes or a comment. 6488 * 6489 * @param line the line to be searched. 6490 * @param searchChar the char to find. 6491 * @param searchStart the start position on the line (default is 0). 6492 * @return the position on the line or string::npos if not found. 6493 */ 6494 size_t ASFormatter::findNextChar(const string& line, char searchChar, int searchStart /*0*/) const 6495 { 6496 // find the next searchChar 6497 size_t i; 6498 for (i = searchStart; i < line.length(); i++) 6499 { 6500 if (line.compare(i, 2, "//") == 0) 6501 return string::npos; 6502 if (line.compare(i, 2, "/*") == 0) 6503 { 6504 size_t endComment = line.find("*/", i + 2); 6505 if (endComment == string::npos) 6506 return string::npos; 6507 i = endComment + 2; 6508 if (i >= line.length()) 6509 return string::npos; 6510 } 6511 if (line[i] == '"' 6512 || (line[i] == '\'' && !isDigitSeparator(line, i))) 6513 { 6514 char quote = line[i]; 6515 while (i < line.length()) 6516 { 6517 size_t endQuote = line.find(quote, i + 1); 6518 if (endQuote == string::npos) 6519 return string::npos; 6520 i = endQuote; 6521 if (line[endQuote - 1] != '\\') // check for '\"' 6522 break; 6523 if (line[endQuote - 2] == '\\') // check for '\\' 6524 break; 6525 } 6526 } 6527 6528 if (line[i] == searchChar) 6529 break; 6530 6531 // for now don't process C# 'delegate' braces 6532 // do this last in case the search char is a '{' 6533 if (line[i] == '{') 6534 return string::npos; 6535 } 6536 if (i >= line.length()) // didn't find searchChar 6537 return string::npos; 6538 6539 return i; 6540 } 6541 6542 /** 6543 * Find split point for break/attach return type. 6544 */ 6545 void ASFormatter::findReturnTypeSplitPoint(const string& firstLine) 6546 { 6547 assert((isBraceType(braceTypeStack->back(), NULL_TYPE) 6548 || isBraceType(braceTypeStack->back(), DEFINITION_TYPE))); 6549 assert(shouldBreakReturnType || shouldBreakReturnTypeDecl 6550 || shouldAttachReturnType || shouldAttachReturnTypeDecl); 6551 6552 bool isFirstLine = true; 6553 bool isInComment_ = false; 6554 bool isInQuote_ = false; 6555 bool foundSplitPoint = false; 6556 bool isAlreadyBroken = false; 6557 char quoteChar_ = ' '; 6558 char currNonWSChar = ' '; 6559 char prevNonWSChar = ' '; 6560 size_t parenCount = 0; 6561 size_t squareCount = 0; 6562 size_t angleCount = 0; 6563 size_t breakLineNum = 0; 6564 size_t breakCharNum = string::npos; 6565 string line = firstLine; 6566 6567 // Process the lines until a ';' or '{'. 6568 ASPeekStream stream(sourceIterator); 6569 while (stream.hasMoreLines() || isFirstLine) 6570 { 6571 if (isFirstLine) 6572 isFirstLine = false; 6573 else 6574 { 6575 if (isInQuote_) 6576 return; 6577 line = stream.peekNextLine(); 6578 if (!foundSplitPoint) 6579 ++breakLineNum; 6580 } 6581 size_t firstCharNum = line.find_first_not_of(" \t"); 6582 if (firstCharNum == string::npos) 6583 continue; 6584 if (line[firstCharNum] == '#') 6585 { 6586 // don't attach to a preprocessor 6587 if (shouldAttachReturnType || shouldAttachReturnTypeDecl) 6588 return; 6589 else 6590 continue; 6591 } 6592 // parse the line 6593 for (size_t i = 0; i < line.length(); i++) 6594 { 6595 if (!isWhiteSpace(line[i])) 6596 { 6597 prevNonWSChar = currNonWSChar; 6598 currNonWSChar = line[i]; 6599 } 6600 else if (line[i] == '\t' && shouldConvertTabs) 6601 { 6602 size_t tabSize = getTabLength(); 6603 size_t numSpaces = tabSize - ((tabIncrementIn + i) % tabSize); 6604 line.replace(i, 1, numSpaces, ' '); 6605 currentChar = line[i]; 6606 } 6607 if (line.compare(i, 2, "/*") == 0) 6608 isInComment_ = true; 6609 if (isInComment_) 6610 { 6611 if (line.compare(i, 2, "*/") == 0) 6612 { 6613 isInComment_ = false; 6614 ++i; 6615 } 6616 continue; 6617 } 6618 if (line[i] == '\\') 6619 { 6620 ++i; 6621 continue; 6622 } 6623 6624 if (isInQuote_) 6625 { 6626 if (line[i] == quoteChar_) 6627 isInQuote_ = false; 6628 continue; 6629 } 6630 6631 if (line[i] == '"' 6632 || (line[i] == '\'' && !isDigitSeparator(line, i))) 6633 { 6634 isInQuote_ = true; 6635 quoteChar_ = line[i]; 6636 continue; 6637 } 6638 if (line.compare(i, 2, "//") == 0) 6639 { 6640 i = line.length(); 6641 continue; 6642 } 6643 // not in quote or comment 6644 if (!foundSplitPoint) 6645 { 6646 if (line[i] == '<') 6647 { 6648 ++angleCount; 6649 continue; 6650 } 6651 if (line[i] == '>') 6652 { 6653 if (angleCount) 6654 --angleCount; 6655 if (!angleCount) 6656 { 6657 size_t nextCharNum = line.find_first_not_of(" \t*&", i + 1); 6658 if (nextCharNum == string::npos) 6659 { 6660 breakCharNum = string::npos; 6661 continue; 6662 } 6663 if (line[nextCharNum] != ':') // scope operator 6664 breakCharNum = nextCharNum; 6665 } 6666 continue; 6667 } 6668 if (angleCount) 6669 continue; 6670 if (line[i] == '[') 6671 { 6672 ++squareCount; 6673 continue; 6674 } 6675 if (line[i] == ']') 6676 { 6677 if (squareCount) 6678 --squareCount; 6679 continue; 6680 } 6681 // an assignment before the parens is not a function 6682 if (line[i] == '=') 6683 return; 6684 if (isWhiteSpace(line[i]) || line[i] == '*' || line[i] == '&') 6685 { 6686 size_t nextNum = line.find_first_not_of(" \t", i + 1); 6687 if (nextNum == string::npos) 6688 breakCharNum = string::npos; 6689 else 6690 { 6691 if (line.length() > nextNum + 1 6692 && line[nextNum] == ':' && line[nextNum + 1] == ':') 6693 i = --nextNum; 6694 else if (line[nextNum] != '(') 6695 breakCharNum = string::npos; 6696 } 6697 continue; 6698 } 6699 if ((isLegalNameChar(line[i]) || line[i] == '~') 6700 && breakCharNum == string::npos) 6701 { 6702 breakCharNum = i; 6703 if (isLegalNameChar(line[i]) 6704 && findKeyword(line, i, AS_OPERATOR)) 6705 { 6706 if (breakCharNum == firstCharNum) 6707 isAlreadyBroken = true; 6708 foundSplitPoint = true; 6709 // find the operator, may be parens 6710 size_t parenNum = 6711 line.find_first_not_of(" \t", i + AS_OPERATOR.length()); 6712 if (parenNum == string::npos) 6713 return; 6714 // find paren after the operator 6715 parenNum = line.find('(', parenNum + 1); 6716 if (parenNum == string::npos) 6717 return; 6718 i = --parenNum; 6719 } 6720 continue; 6721 } 6722 if (line[i] == ':' 6723 && line.length() > i + 1 6724 && line[i + 1] == ':') 6725 { 6726 size_t nextCharNum = line.find_first_not_of(" \t:", i + 1); 6727 if (nextCharNum == string::npos) 6728 return; 6729 6730 if (isLegalNameChar(line[nextCharNum]) 6731 && findKeyword(line, nextCharNum, AS_OPERATOR)) 6732 { 6733 i = nextCharNum; 6734 if (breakCharNum == firstCharNum) 6735 isAlreadyBroken = true; 6736 foundSplitPoint = true; 6737 // find the operator, may be parens 6738 size_t parenNum = 6739 line.find_first_not_of(" \t", i + AS_OPERATOR.length()); 6740 if (parenNum == string::npos) 6741 return; 6742 // find paren after the operator 6743 parenNum = line.find('(', parenNum + 1); 6744 if (parenNum == string::npos) 6745 return; 6746 i = --parenNum; 6747 } 6748 else 6749 i = --nextCharNum; 6750 continue; 6751 } 6752 if (line[i] == '(' && !squareCount) 6753 { 6754 // is line is already broken? 6755 if (breakCharNum == firstCharNum && breakLineNum > 0) 6756 isAlreadyBroken = true; 6757 ++parenCount; 6758 foundSplitPoint = true; 6759 continue; 6760 } 6761 } 6762 // end !foundSplitPoint 6763 if (line[i] == '(') 6764 { 6765 // consecutive ')(' parens is probably a function pointer 6766 if (prevNonWSChar == ')' && !parenCount) 6767 return; 6768 ++parenCount; 6769 continue; 6770 } 6771 if (line[i] == ')') 6772 { 6773 if (parenCount) 6774 --parenCount; 6775 continue; 6776 } 6777 if (line[i] == '{') 6778 { 6779 if (shouldBreakReturnType && foundSplitPoint && !isAlreadyBroken) 6780 { 6781 methodBreakCharNum = breakCharNum; 6782 methodBreakLineNum = breakLineNum; 6783 } 6784 if (shouldAttachReturnType && foundSplitPoint && isAlreadyBroken) 6785 { 6786 methodAttachCharNum = breakCharNum; 6787 methodAttachLineNum = breakLineNum; 6788 } 6789 return; 6790 } 6791 if (line[i] == ';') 6792 { 6793 if (shouldBreakReturnTypeDecl && foundSplitPoint && !isAlreadyBroken) 6794 { 6795 methodBreakCharNum = breakCharNum; 6796 methodBreakLineNum = breakLineNum; 6797 } 6798 if ((shouldAttachReturnTypeDecl && foundSplitPoint && isAlreadyBroken)) 6799 { 6800 methodAttachCharNum = breakCharNum; 6801 methodAttachLineNum = breakLineNum; 6802 } 6803 return; 6804 } 6805 if (line[i] == '}') 6806 return; 6807 } // end of for loop 6808 if (!foundSplitPoint) 6809 breakCharNum = string::npos; 6810 } // end of while loop 6811 } 6812 6813 /** 6814 * Look ahead in the file to see if a struct has access modifiers. 6815 * 6816 * @param firstLine a reference to the line to indent. 6817 * @param index the current line index. 6818 * @return true if the struct has access modifiers. 6819 */ 6820 bool ASFormatter::isStructAccessModified(const string& firstLine, size_t index) const 6821 { 6822 assert(firstLine[index] == '{'); 6823 assert(isCStyle()); 6824 6825 bool isFirstLine = true; 6826 size_t braceCount = 1; 6827 string nextLine_ = firstLine.substr(index + 1); 6828 ASPeekStream stream(sourceIterator); 6829 6830 // find the first non-blank text, bypassing all comments and quotes. 6831 bool isInComment_ = false; 6832 bool isInQuote_ = false; 6833 char quoteChar_ = ' '; 6834 while (stream.hasMoreLines() || isFirstLine) 6835 { 6836 if (isFirstLine) 6837 isFirstLine = false; 6838 else 6839 nextLine_ = stream.peekNextLine(); 6840 // parse the line 6841 for (size_t i = 0; i < nextLine_.length(); i++) 6842 { 6843 if (isWhiteSpace(nextLine_[i])) 6844 continue; 6845 if (nextLine_.compare(i, 2, "/*") == 0) 6846 isInComment_ = true; 6847 if (isInComment_) 6848 { 6849 if (nextLine_.compare(i, 2, "*/") == 0) 6850 { 6851 isInComment_ = false; 6852 ++i; 6853 } 6854 continue; 6855 } 6856 if (nextLine_[i] == '\\') 6857 { 6858 ++i; 6859 continue; 6860 } 6861 6862 if (isInQuote_) 6863 { 6864 if (nextLine_[i] == quoteChar_) 6865 isInQuote_ = false; 6866 continue; 6867 } 6868 6869 if (nextLine_[i] == '"' 6870 || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i))) 6871 { 6872 isInQuote_ = true; 6873 quoteChar_ = nextLine_[i]; 6874 continue; 6875 } 6876 if (nextLine_.compare(i, 2, "//") == 0) 6877 { 6878 i = nextLine_.length(); 6879 continue; 6880 } 6881 // handle braces 6882 if (nextLine_[i] == '{') 6883 ++braceCount; 6884 if (nextLine_[i] == '}') 6885 --braceCount; 6886 if (braceCount == 0) 6887 return false; 6888 // check for access modifiers 6889 if (isCharPotentialHeader(nextLine_, i)) 6890 { 6891 if (findKeyword(nextLine_, i, AS_PUBLIC) 6892 || findKeyword(nextLine_, i, AS_PRIVATE) 6893 || findKeyword(nextLine_, i, AS_PROTECTED)) 6894 return true; 6895 string name = getCurrentWord(nextLine_, i); 6896 i += name.length() - 1; 6897 } 6898 } // end of for loop 6899 } // end of while loop 6900 6901 return false; 6902 } 6903 6904 /** 6905 * Look ahead in the file to see if a preprocessor block is indentable. 6906 * 6907 * @param firstLine a reference to the line to indent. 6908 * @param index the current line index. 6909 * @return true if the block is indentable. 6910 */ 6911 bool ASFormatter::isIndentablePreprocessorBlock(const string& firstLine, size_t index) 6912 { 6913 assert(firstLine[index] == '#'); 6914 6915 bool isFirstLine = true; 6916 bool isInIndentableBlock = false; 6917 bool blockContainsBraces = false; 6918 bool blockContainsDefineContinuation = false; 6919 bool isInClassConstructor = false; 6920 bool isPotentialHeaderGuard = false; // ifndef is first preproc statement 6921 bool isPotentialHeaderGuard2 = false; // define is within the first proproc 6922 int numBlockIndents = 0; 6923 int lineParenCount = 0; 6924 string nextLine_ = firstLine.substr(index); 6925 auto stream = make_shared<ASPeekStream>(sourceIterator); 6926 6927 // find end of the block, bypassing all comments and quotes. 6928 bool isInComment_ = false; 6929 bool isInQuote_ = false; 6930 char quoteChar_ = ' '; 6931 while (stream->hasMoreLines() || isFirstLine) 6932 { 6933 if (isFirstLine) 6934 isFirstLine = false; 6935 else 6936 nextLine_ = stream->peekNextLine(); 6937 // parse the line 6938 for (size_t i = 0; i < nextLine_.length(); i++) 6939 { 6940 if (isWhiteSpace(nextLine_[i])) 6941 continue; 6942 if (nextLine_.compare(i, 2, "/*") == 0) 6943 isInComment_ = true; 6944 if (isInComment_) 6945 { 6946 if (nextLine_.compare(i, 2, "*/") == 0) 6947 { 6948 isInComment_ = false; 6949 ++i; 6950 } 6951 continue; 6952 } 6953 if (nextLine_[i] == '\\') 6954 { 6955 ++i; 6956 continue; 6957 } 6958 if (isInQuote_) 6959 { 6960 if (nextLine_[i] == quoteChar_) 6961 isInQuote_ = false; 6962 continue; 6963 } 6964 6965 if (nextLine_[i] == '"' 6966 || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i))) 6967 { 6968 isInQuote_ = true; 6969 quoteChar_ = nextLine_[i]; 6970 continue; 6971 } 6972 if (nextLine_.compare(i, 2, "//") == 0) 6973 { 6974 i = nextLine_.length(); 6975 continue; 6976 } 6977 // handle preprocessor statement 6978 if (nextLine_[i] == '#') 6979 { 6980 string preproc = ASBeautifier::extractPreprocessorStatement(nextLine_); 6981 if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef 6982 { 6983 numBlockIndents += 1; 6984 isInIndentableBlock = true; 6985 // flag first preprocessor conditional for header include guard check 6986 if (!processedFirstConditional) 6987 { 6988 processedFirstConditional = true; 6989 isFirstPreprocConditional = true; 6990 if (isNDefPreprocStatement(nextLine_, preproc)) 6991 isPotentialHeaderGuard = true; 6992 } 6993 } 6994 else if (preproc == "endif") 6995 { 6996 if (numBlockIndents > 0) 6997 numBlockIndents -= 1; 6998 // must exit BOTH loops 6999 if (numBlockIndents == 0) 7000 goto EndOfWhileLoop; 7001 } 7002 else if (preproc == "define") 7003 { 7004 if (nextLine_[nextLine_.length() - 1] == '\\') 7005 blockContainsDefineContinuation = true; 7006 // check for potential header include guards 7007 else if (isPotentialHeaderGuard && numBlockIndents == 1) 7008 isPotentialHeaderGuard2 = true; 7009 } 7010 i = nextLine_.length(); 7011 continue; 7012 } 7013 // handle exceptions 7014 if (nextLine_[i] == '{' || nextLine_[i] == '}') 7015 blockContainsBraces = true; 7016 else if (nextLine_[i] == '(') 7017 ++lineParenCount; 7018 else if (nextLine_[i] == ')') 7019 --lineParenCount; 7020 else if (nextLine_[i] == ':') 7021 { 7022 // check for '::' 7023 if (nextLine_.length() > i + 1 && nextLine_[i + 1] == ':') 7024 ++i; 7025 else 7026 isInClassConstructor = true; 7027 } 7028 // bypass unnecessary parsing - must exit BOTH loops 7029 if (blockContainsBraces || isInClassConstructor || blockContainsDefineContinuation) 7030 goto EndOfWhileLoop; 7031 } // end of for loop, end of line 7032 if (lineParenCount != 0) 7033 break; 7034 } // end of while loop 7035 EndOfWhileLoop: 7036 preprocBlockEnd = sourceIterator->tellg(); 7037 if (preprocBlockEnd < 0) 7038 preprocBlockEnd = sourceIterator->getStreamLength(); 7039 if (blockContainsBraces 7040 || isInClassConstructor 7041 || blockContainsDefineContinuation 7042 || lineParenCount != 0 7043 || numBlockIndents != 0) 7044 isInIndentableBlock = false; 7045 // find next executable instruction 7046 // this WILL RESET the get pointer 7047 string nextText = peekNextText("", false, stream); 7048 // bypass header include guards 7049 if (isFirstPreprocConditional) 7050 { 7051 isFirstPreprocConditional = false; 7052 if (nextText.empty() && isPotentialHeaderGuard2) 7053 { 7054 isInIndentableBlock = false; 7055 preprocBlockEnd = 0; 7056 } 7057 } 7058 // this allows preprocessor blocks within this block to be indented 7059 if (!isInIndentableBlock) 7060 preprocBlockEnd = 0; 7061 // peekReset() is done by previous peekNextText() 7062 return isInIndentableBlock; 7063 } 7064 7065 bool ASFormatter::isNDefPreprocStatement(const string& nextLine_, const string& preproc) const 7066 { 7067 if (preproc == "ifndef") 7068 return true; 7069 // check for '!defined' 7070 if (preproc == "if") 7071 { 7072 size_t i = nextLine_.find('!'); 7073 if (i == string::npos) 7074 return false; 7075 i = nextLine_.find_first_not_of(" \t", ++i); 7076 if (i != string::npos && nextLine_.compare(i, 7, "defined") == 0) 7077 return true; 7078 } 7079 return false; 7080 } 7081 7082 /** 7083 * Check to see if this is an EXEC SQL statement. 7084 * 7085 * @param line a reference to the line to indent. 7086 * @param index the current line index. 7087 * @return true if the statement is EXEC SQL. 7088 */ 7089 bool ASFormatter::isExecSQL(const string& line, size_t index) const 7090 { 7091 if (line[index] != 'e' && line[index] != 'E') // quick check to reject most 7092 return false; 7093 string word; 7094 if (isCharPotentialHeader(line, index)) 7095 word = getCurrentWord(line, index); 7096 for (size_t i = 0; i < word.length(); i++) 7097 word[i] = (char) toupper(word[i]); 7098 if (word != "EXEC") 7099 return false; 7100 size_t index2 = index + word.length(); 7101 index2 = line.find_first_not_of(" \t", index2); 7102 if (index2 == string::npos) 7103 return false; 7104 word.erase(); 7105 if (isCharPotentialHeader(line, index2)) 7106 word = getCurrentWord(line, index2); 7107 for (size_t i = 0; i < word.length(); i++) 7108 word[i] = (char) toupper(word[i]); 7109 if (word != "SQL") 7110 return false; 7111 return true; 7112 } 7113 7114 /** 7115 * The continuation lines must be adjusted so the leading spaces 7116 * is equivalent to the text on the opening line. 7117 * 7118 * Updates currentLine and charNum. 7119 */ 7120 void ASFormatter::trimContinuationLine() 7121 { 7122 size_t len = currentLine.length(); 7123 size_t tabSize = getTabLength(); 7124 charNum = 0; 7125 7126 if (leadingSpaces > 0 && len > 0) 7127 { 7128 size_t i; 7129 size_t continuationIncrementIn = 0; 7130 for (i = 0; (i < len) && (i + continuationIncrementIn < leadingSpaces); i++) 7131 { 7132 if (!isWhiteSpace(currentLine[i])) // don't delete any text 7133 { 7134 if (i < continuationIncrementIn) 7135 leadingSpaces = i + tabIncrementIn; 7136 continuationIncrementIn = tabIncrementIn; 7137 break; 7138 } 7139 if (currentLine[i] == '\t') 7140 continuationIncrementIn += tabSize - 1 - ((continuationIncrementIn + i) % tabSize); 7141 } 7142 7143 if ((int) continuationIncrementIn == tabIncrementIn) 7144 charNum = i; 7145 else 7146 { 7147 // build a new line with the equivalent leading chars 7148 string newLine; 7149 int leadingChars = 0; 7150 if ((int) leadingSpaces > tabIncrementIn) 7151 leadingChars = leadingSpaces - tabIncrementIn; 7152 newLine.append(leadingChars, ' '); 7153 newLine.append(currentLine, i, len - i); 7154 currentLine = newLine; 7155 charNum = leadingChars; 7156 if (currentLine.length() == 0) 7157 currentLine = string(" "); // a null is inserted if this is not done 7158 } 7159 if (i >= len) 7160 charNum = 0; 7161 } 7162 } 7163 7164 /** 7165 * Determine if a header is a closing header 7166 * 7167 * @return true if the header is a closing header. 7168 */ 7169 bool ASFormatter::isClosingHeader(const string* header) const 7170 { 7171 return (header == &AS_ELSE 7172 || header == &AS_CATCH 7173 || header == &AS_FINALLY); 7174 } 7175 7176 /** 7177 * Determine if a * following a closing paren is immediately. 7178 * after a cast. If so it is a deference and not a multiply. 7179 * e.g. "(int*) *ptr" is a deference. 7180 */ 7181 bool ASFormatter::isImmediatelyPostCast() const 7182 { 7183 assert(previousNonWSChar == ')' && currentChar == '*'); 7184 // find preceding closing paren on currentLine or readyFormattedLine 7185 string line; // currentLine or readyFormattedLine 7186 size_t paren = currentLine.rfind(')', charNum); 7187 if (paren != string::npos) 7188 line = currentLine; 7189 // if not on currentLine it must be on the previous line 7190 else 7191 { 7192 line = readyFormattedLine; 7193 paren = line.rfind(')'); 7194 if (paren == string::npos) 7195 return false; 7196 } 7197 if (paren == 0) 7198 return false; 7199 7200 // find character preceding the closing paren 7201 size_t lastChar = line.find_last_not_of(" \t", paren - 1); 7202 if (lastChar == string::npos) 7203 return false; 7204 // check for pointer cast 7205 if (line[lastChar] == '*') 7206 return true; 7207 return false; 7208 } 7209 7210 /** 7211 * Determine if a < is a template definition or instantiation. 7212 * Sets the class variables isInTemplate and templateDepth. 7213 */ 7214 void ASFormatter::checkIfTemplateOpener() 7215 { 7216 assert(!isInTemplate && currentChar == '<'); 7217 7218 // find first char after the '<' operators 7219 size_t firstChar = currentLine.find_first_not_of("< \t", charNum); 7220 if (firstChar == string::npos 7221 || currentLine[firstChar] == '=') 7222 { 7223 // this is not a template -> leave... 7224 isInTemplate = false; 7225 return; 7226 } 7227 7228 bool isFirstLine = true; 7229 int parenDepth_ = 0; 7230 int maxTemplateDepth = 0; 7231 templateDepth = 0; 7232 string nextLine_ = currentLine.substr(charNum); 7233 ASPeekStream stream(sourceIterator); 7234 7235 // find the angle braces, bypassing all comments and quotes. 7236 bool isInComment_ = false; 7237 bool isInQuote_ = false; 7238 char quoteChar_ = ' '; 7239 while (stream.hasMoreLines() || isFirstLine) 7240 { 7241 if (isFirstLine) 7242 isFirstLine = false; 7243 else 7244 nextLine_ = stream.peekNextLine(); 7245 // parse the line 7246 for (size_t i = 0; i < nextLine_.length(); i++) 7247 { 7248 char currentChar_ = nextLine_[i]; 7249 if (isWhiteSpace(currentChar_)) 7250 continue; 7251 if (nextLine_.compare(i, 2, "/*") == 0) 7252 isInComment_ = true; 7253 if (isInComment_) 7254 { 7255 if (nextLine_.compare(i, 2, "*/") == 0) 7256 { 7257 isInComment_ = false; 7258 ++i; 7259 } 7260 continue; 7261 } 7262 if (currentChar_ == '\\') 7263 { 7264 ++i; 7265 continue; 7266 } 7267 7268 if (isInQuote_) 7269 { 7270 if (currentChar_ == quoteChar_) 7271 isInQuote_ = false; 7272 continue; 7273 } 7274 7275 if (currentChar_ == '"' 7276 || (currentChar_ == '\'' && !isDigitSeparator(nextLine_, i))) 7277 { 7278 isInQuote_ = true; 7279 quoteChar_ = currentChar_; 7280 continue; 7281 } 7282 if (nextLine_.compare(i, 2, "//") == 0) 7283 { 7284 i = nextLine_.length(); 7285 continue; 7286 } 7287 7288 // not in a comment or quote 7289 if (currentChar_ == '<') 7290 { 7291 ++templateDepth; 7292 ++maxTemplateDepth; 7293 continue; 7294 } 7295 else if (currentChar_ == '>') 7296 { 7297 --templateDepth; 7298 if (templateDepth == 0) 7299 { 7300 if (parenDepth_ == 0) 7301 { 7302 // this is a template! 7303 isInTemplate = true; 7304 templateDepth = maxTemplateDepth; 7305 } 7306 return; 7307 } 7308 continue; 7309 } 7310 else if (currentChar_ == '(' || currentChar_ == ')') 7311 { 7312 if (currentChar_ == '(') 7313 ++parenDepth_; 7314 else 7315 --parenDepth_; 7316 if (parenDepth_ >= 0) 7317 continue; 7318 // this is not a template -> leave... 7319 isInTemplate = false; 7320 templateDepth = 0; 7321 return; 7322 } 7323 else if (nextLine_.compare(i, 2, AS_AND) == 0 7324 || nextLine_.compare(i, 2, AS_OR) == 0) 7325 { 7326 // this is not a template -> leave... 7327 isInTemplate = false; 7328 templateDepth = 0; 7329 return; 7330 } 7331 else if (currentChar_ == ',' // comma, e.g. A<int, char> 7332 || currentChar_ == '&' // reference, e.g. A<int&> 7333 || currentChar_ == '*' // pointer, e.g. A<int*> 7334 || currentChar_ == '^' // C++/CLI managed pointer, e.g. A<int^> 7335 || currentChar_ == ':' // ::, e.g. std::string 7336 || currentChar_ == '=' // assign e.g. default parameter 7337 || currentChar_ == '[' // [] e.g. string[] 7338 || currentChar_ == ']' // [] e.g. string[] 7339 || currentChar_ == '(' // (...) e.g. function definition 7340 || currentChar_ == ')' // (...) e.g. function definition 7341 || (isJavaStyle() && currentChar_ == '?') // Java wildcard 7342 ) 7343 { 7344 continue; 7345 } 7346 else if (!isLegalNameChar(currentChar_)) 7347 { 7348 // this is not a template -> leave... 7349 isInTemplate = false; 7350 templateDepth = 0; 7351 return; 7352 } 7353 string name = getCurrentWord(nextLine_, i); 7354 i += name.length() - 1; 7355 } // end for loop 7356 } // end while loop 7357 } 7358 7359 void ASFormatter::updateFormattedLineSplitPoints(char appendedChar) 7360 { 7361 assert(maxCodeLength != string::npos); 7362 assert(formattedLine.length() > 0); 7363 7364 if (!isOkToSplitFormattedLine()) 7365 return; 7366 7367 char nextChar = peekNextChar(); 7368 7369 // don't split before an end of line comment 7370 if (nextChar == '/') 7371 return; 7372 7373 // don't split before or after a brace 7374 if (appendedChar == '{' || appendedChar == '}' 7375 || previousNonWSChar == '{' || previousNonWSChar == '}' 7376 || nextChar == '{' || nextChar == '}' 7377 || currentChar == '{' || currentChar == '}') // currentChar tests for an appended brace 7378 return; 7379 7380 // don't split before or after a block paren 7381 if (appendedChar == '[' || appendedChar == ']' 7382 || previousNonWSChar == '[' 7383 || nextChar == '[' || nextChar == ']') 7384 return; 7385 7386 if (isWhiteSpace(appendedChar)) 7387 { 7388 if (nextChar != ')' // space before a closing paren 7389 && nextChar != '(' // space before an opening paren 7390 && nextChar != '/' // space before a comment 7391 && nextChar != ':' // space before a colon 7392 && currentChar != ')' // appended space before and after a closing paren 7393 && currentChar != '(' // appended space before and after a opening paren 7394 && previousNonWSChar != '(' // decided at the '(' 7395 // don't break before a pointer or reference aligned to type 7396 && !(nextChar == '*' 7397 && !isCharPotentialOperator(previousNonWSChar) 7398 && pointerAlignment == PTR_ALIGN_TYPE) 7399 && !(nextChar == '&' 7400 && !isCharPotentialOperator(previousNonWSChar) 7401 && (referenceAlignment == REF_ALIGN_TYPE 7402 || (referenceAlignment == REF_SAME_AS_PTR && pointerAlignment == PTR_ALIGN_TYPE))) 7403 ) 7404 { 7405 if (formattedLine.length() - 1 <= maxCodeLength) 7406 maxWhiteSpace = formattedLine.length() - 1; 7407 else 7408 maxWhiteSpacePending = formattedLine.length() - 1; 7409 } 7410 } 7411 // unpadded closing parens may split after the paren (counts as whitespace) 7412 else if (appendedChar == ')') 7413 { 7414 if (nextChar != ')' 7415 && nextChar != ' ' 7416 && nextChar != ';' 7417 && nextChar != ',' 7418 && nextChar != '.' 7419 && !(nextChar == '-' && pointerSymbolFollows())) // check for -> 7420 { 7421 if (formattedLine.length() <= maxCodeLength) 7422 maxWhiteSpace = formattedLine.length(); 7423 else 7424 maxWhiteSpacePending = formattedLine.length(); 7425 } 7426 } 7427 // unpadded commas may split after the comma 7428 else if (appendedChar == ',') 7429 { 7430 if (formattedLine.length() <= maxCodeLength) 7431 maxComma = formattedLine.length(); 7432 else 7433 maxCommaPending = formattedLine.length(); 7434 } 7435 else if (appendedChar == '(') 7436 { 7437 if (nextChar != ')' && nextChar != '(' && nextChar != '"' && nextChar != '\'') 7438 { 7439 // if follows an operator break before 7440 size_t parenNum; 7441 if (previousNonWSChar != ' ' && isCharPotentialOperator(previousNonWSChar)) 7442 parenNum = formattedLine.length() - 1; 7443 else 7444 parenNum = formattedLine.length(); 7445 if (formattedLine.length() <= maxCodeLength) 7446 maxParen = parenNum; 7447 else 7448 maxParenPending = parenNum; 7449 } 7450 } 7451 else if (appendedChar == ';') 7452 { 7453 if (nextChar != ' ' && nextChar != '}' && nextChar != '/') // check for following comment 7454 { 7455 if (formattedLine.length() <= maxCodeLength) 7456 maxSemi = formattedLine.length(); 7457 else 7458 maxSemiPending = formattedLine.length(); 7459 } 7460 } 7461 } 7462 7463 void ASFormatter::updateFormattedLineSplitPointsOperator(const string& sequence) 7464 { 7465 assert(maxCodeLength != string::npos); 7466 assert(formattedLine.length() > 0); 7467 7468 if (!isOkToSplitFormattedLine()) 7469 return; 7470 7471 char nextChar = peekNextChar(); 7472 7473 // don't split before an end of line comment 7474 if (nextChar == '/') 7475 return; 7476 7477 // check for logical conditional 7478 if (sequence == "||" || sequence == "&&" || sequence == "or" || sequence == "and") 7479 { 7480 if (shouldBreakLineAfterLogical) 7481 { 7482 if (formattedLine.length() <= maxCodeLength) 7483 maxAndOr = formattedLine.length(); 7484 else 7485 maxAndOrPending = formattedLine.length(); 7486 } 7487 else 7488 { 7489 // adjust for leading space in the sequence 7490 size_t sequenceLength = sequence.length(); 7491 if (formattedLine.length() > sequenceLength 7492 && isWhiteSpace(formattedLine[formattedLine.length() - sequenceLength - 1])) 7493 sequenceLength++; 7494 if (formattedLine.length() - sequenceLength <= maxCodeLength) 7495 maxAndOr = formattedLine.length() - sequenceLength; 7496 else 7497 maxAndOrPending = formattedLine.length() - sequenceLength; 7498 } 7499 } 7500 // comparison operators will split after the operator (counts as whitespace) 7501 else if (sequence == "==" || sequence == "!=" || sequence == ">=" || sequence == "<=") 7502 { 7503 if (formattedLine.length() <= maxCodeLength) 7504 maxWhiteSpace = formattedLine.length(); 7505 else 7506 maxWhiteSpacePending = formattedLine.length(); 7507 } 7508 // unpadded operators that will split BEFORE the operator (counts as whitespace) 7509 else if (sequence == "+" || sequence == "-" || sequence == "?") 7510 { 7511 if (charNum > 0 7512 && !(sequence == "+" && isInExponent()) 7513 && !(sequence == "-" && isInExponent()) 7514 && (isLegalNameChar(currentLine[charNum - 1]) 7515 || currentLine[charNum - 1] == ')' 7516 || currentLine[charNum - 1] == ']' 7517 || currentLine[charNum - 1] == '\"')) 7518 { 7519 if (formattedLine.length() - 1 <= maxCodeLength) 7520 maxWhiteSpace = formattedLine.length() - 1; 7521 else 7522 maxWhiteSpacePending = formattedLine.length() - 1; 7523 } 7524 } 7525 // unpadded operators that will USUALLY split AFTER the operator (counts as whitespace) 7526 else if (sequence == "=" || sequence == ":") 7527 { 7528 // split BEFORE if the line is too long 7529 // do NOT use <= here, must allow for a brace attached to an array 7530 size_t splitPoint = 0; 7531 if (formattedLine.length() < maxCodeLength) 7532 splitPoint = formattedLine.length(); 7533 else 7534 splitPoint = formattedLine.length() - 1; 7535 // padded or unpadded arrays 7536 if (previousNonWSChar == ']') 7537 { 7538 if (formattedLine.length() - 1 <= maxCodeLength) 7539 maxWhiteSpace = splitPoint; 7540 else 7541 maxWhiteSpacePending = splitPoint; 7542 } 7543 else if (charNum > 0 7544 && (isLegalNameChar(currentLine[charNum - 1]) 7545 || currentLine[charNum - 1] == ')' 7546 || currentLine[charNum - 1] == ']')) 7547 { 7548 if (formattedLine.length() <= maxCodeLength) 7549 maxWhiteSpace = splitPoint; 7550 else 7551 maxWhiteSpacePending = splitPoint; 7552 } 7553 } 7554 } 7555 7556 /** 7557 * Update the split point when a pointer or reference is formatted. 7558 * The argument is the maximum index of the last whitespace character. 7559 */ 7560 void ASFormatter::updateFormattedLineSplitPointsPointerOrReference(size_t index) 7561 { 7562 assert(maxCodeLength != string::npos); 7563 assert(formattedLine.length() > 0); 7564 assert(index < formattedLine.length()); 7565 7566 if (!isOkToSplitFormattedLine()) 7567 return; 7568 7569 if (index < maxWhiteSpace) // just in case 7570 return; 7571 7572 if (index <= maxCodeLength) 7573 maxWhiteSpace = index; 7574 else 7575 maxWhiteSpacePending = index; 7576 } 7577 7578 bool ASFormatter::isOkToSplitFormattedLine() 7579 { 7580 assert(maxCodeLength != string::npos); 7581 // Is it OK to split the line? 7582 if (shouldKeepLineUnbroken 7583 || isInLineComment 7584 || isInComment 7585 || isInQuote 7586 || isInCase 7587 || isInPreprocessor 7588 || isInExecSQL 7589 || isInAsm || isInAsmOneLine || isInAsmBlock 7590 || isInTemplate) 7591 return false; 7592 7593 if (!isOkToBreakBlock(braceTypeStack->back()) && currentChar != '{') 7594 { 7595 shouldKeepLineUnbroken = true; 7596 clearFormattedLineSplitPoints(); 7597 return false; 7598 } 7599 if (isBraceType(braceTypeStack->back(), ARRAY_TYPE)) 7600 { 7601 shouldKeepLineUnbroken = true; 7602 if (!isBraceType(braceTypeStack->back(), ARRAY_NIS_TYPE)) 7603 clearFormattedLineSplitPoints(); 7604 return false; 7605 } 7606 return true; 7607 } 7608 7609 /* This is called if the option maxCodeLength is set. 7610 */ 7611 void ASFormatter::testForTimeToSplitFormattedLine() 7612 { 7613 // DO NOT ASSERT maxCodeLength HERE 7614 // should the line be split 7615 if (formattedLine.length() > maxCodeLength && !isLineReady) 7616 { 7617 size_t splitPoint = findFormattedLineSplitPoint(); 7618 if (splitPoint > 0 && splitPoint < formattedLine.length()) 7619 { 7620 string splitLine = formattedLine.substr(splitPoint); 7621 formattedLine = formattedLine.substr(0, splitPoint); 7622 breakLine(true); 7623 formattedLine = splitLine; 7624 // if break-blocks is requested and this is a one-line statement 7625 string nextWord = ASBeautifier::getNextWord(currentLine, charNum - 1); 7626 if (isAppendPostBlockEmptyLineRequested 7627 && (nextWord == "break" || nextWord == "continue")) 7628 { 7629 isAppendPostBlockEmptyLineRequested = false; 7630 isPrependPostBlockEmptyLineRequested = true; 7631 } 7632 else 7633 isPrependPostBlockEmptyLineRequested = false; 7634 // adjust max split points 7635 maxAndOr = (maxAndOr > splitPoint) ? (maxAndOr - splitPoint) : 0; 7636 maxSemi = (maxSemi > splitPoint) ? (maxSemi - splitPoint) : 0; 7637 maxComma = (maxComma > splitPoint) ? (maxComma - splitPoint) : 0; 7638 maxParen = (maxParen > splitPoint) ? (maxParen - splitPoint) : 0; 7639 maxWhiteSpace = (maxWhiteSpace > splitPoint) ? (maxWhiteSpace - splitPoint) : 0; 7640 if (maxSemiPending > 0) 7641 { 7642 maxSemi = (maxSemiPending > splitPoint) ? (maxSemiPending - splitPoint) : 0; 7643 maxSemiPending = 0; 7644 } 7645 if (maxAndOrPending > 0) 7646 { 7647 maxAndOr = (maxAndOrPending > splitPoint) ? (maxAndOrPending - splitPoint) : 0; 7648 maxAndOrPending = 0; 7649 } 7650 if (maxCommaPending > 0) 7651 { 7652 maxComma = (maxCommaPending > splitPoint) ? (maxCommaPending - splitPoint) : 0; 7653 maxCommaPending = 0; 7654 } 7655 if (maxParenPending > 0) 7656 { 7657 maxParen = (maxParenPending > splitPoint) ? (maxParenPending - splitPoint) : 0; 7658 maxParenPending = 0; 7659 } 7660 if (maxWhiteSpacePending > 0) 7661 { 7662 maxWhiteSpace = (maxWhiteSpacePending > splitPoint) ? (maxWhiteSpacePending - splitPoint) : 0; 7663 maxWhiteSpacePending = 0; 7664 } 7665 // don't allow an empty formatted line 7666 size_t firstText = formattedLine.find_first_not_of(" \t"); 7667 if (firstText == string::npos && formattedLine.length() > 0) 7668 { 7669 formattedLine.erase(); 7670 clearFormattedLineSplitPoints(); 7671 if (isWhiteSpace(currentChar)) 7672 for (size_t i = charNum + 1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++) 7673 goForward(1); 7674 } 7675 else if (firstText > 0) 7676 { 7677 formattedLine.erase(0, firstText); 7678 maxSemi = (maxSemi > firstText) ? (maxSemi - firstText) : 0; 7679 maxAndOr = (maxAndOr > firstText) ? (maxAndOr - firstText) : 0; 7680 maxComma = (maxComma > firstText) ? (maxComma - firstText) : 0; 7681 maxParen = (maxParen > firstText) ? (maxParen - firstText) : 0; 7682 maxWhiteSpace = (maxWhiteSpace > firstText) ? (maxWhiteSpace - firstText) : 0; 7683 } 7684 // reset formattedLineCommentNum 7685 if (formattedLineCommentNum != string::npos) 7686 { 7687 formattedLineCommentNum = formattedLine.find("//"); 7688 if (formattedLineCommentNum == string::npos) 7689 formattedLineCommentNum = formattedLine.find("/*"); 7690 } 7691 } 7692 } 7693 } 7694 7695 size_t ASFormatter::findFormattedLineSplitPoint() const 7696 { 7697 assert(maxCodeLength != string::npos); 7698 // determine where to split 7699 size_t minCodeLength = 10; 7700 size_t splitPoint = 0; 7701 splitPoint = maxSemi; 7702 if (maxAndOr >= minCodeLength) 7703 splitPoint = maxAndOr; 7704 if (splitPoint < minCodeLength) 7705 { 7706 splitPoint = maxWhiteSpace; 7707 // use maxParen instead if it is long enough 7708 if (maxParen > splitPoint 7709 || maxParen >= maxCodeLength * .7) 7710 splitPoint = maxParen; 7711 // use maxComma instead if it is long enough 7712 // increasing the multiplier causes more splits at whitespace 7713 if (maxComma > splitPoint 7714 || maxComma >= maxCodeLength * .3) 7715 splitPoint = maxComma; 7716 } 7717 // replace split point with first available break point 7718 if (splitPoint < minCodeLength) 7719 { 7720 splitPoint = string::npos; 7721 if (maxSemiPending > 0 && maxSemiPending < splitPoint) 7722 splitPoint = maxSemiPending; 7723 if (maxAndOrPending > 0 && maxAndOrPending < splitPoint) 7724 splitPoint = maxAndOrPending; 7725 if (maxCommaPending > 0 && maxCommaPending < splitPoint) 7726 splitPoint = maxCommaPending; 7727 if (maxParenPending > 0 && maxParenPending < splitPoint) 7728 splitPoint = maxParenPending; 7729 if (maxWhiteSpacePending > 0 && maxWhiteSpacePending < splitPoint) 7730 splitPoint = maxWhiteSpacePending; 7731 if (splitPoint == string::npos) 7732 splitPoint = 0; 7733 } 7734 // if remaining line after split is too long 7735 else if (formattedLine.length() - splitPoint > maxCodeLength) 7736 { 7737 // if end of the currentLine, find a new split point 7738 size_t newCharNum; 7739 if (!isWhiteSpace(currentChar) && isCharPotentialHeader(currentLine, charNum)) 7740 newCharNum = getCurrentWord(currentLine, charNum).length() + charNum; 7741 else 7742 newCharNum = charNum + 2; 7743 if (newCharNum + 1 > currentLine.length()) 7744 { 7745 // don't move splitPoint from before a conditional to after 7746 if (maxWhiteSpace > splitPoint + 3) 7747 splitPoint = maxWhiteSpace; 7748 if (maxParen > splitPoint) 7749 splitPoint = maxParen; 7750 } 7751 } 7752 7753 return splitPoint; 7754 } 7755 7756 void ASFormatter::clearFormattedLineSplitPoints() 7757 { 7758 maxSemi = 0; 7759 maxAndOr = 0; 7760 maxComma = 0; 7761 maxParen = 0; 7762 maxWhiteSpace = 0; 7763 maxSemiPending = 0; 7764 maxAndOrPending = 0; 7765 maxCommaPending = 0; 7766 maxParenPending = 0; 7767 maxWhiteSpacePending = 0; 7768 } 7769 7770 /** 7771 * Check if a pointer symbol (->) follows on the currentLine. 7772 */ 7773 bool ASFormatter::pointerSymbolFollows() const 7774 { 7775 size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1); 7776 if (peekNum == string::npos || currentLine.compare(peekNum, 2, "->") != 0) 7777 return false; 7778 return true; 7779 } 7780 7781 /** 7782 * Compute the input checksum. 7783 * This is called as an assert so it for is debug config only 7784 */ 7785 bool ASFormatter::computeChecksumIn(const string& currentLine_) 7786 { 7787 for (size_t i = 0; i < currentLine_.length(); i++) 7788 if (!isWhiteSpace(currentLine_[i])) 7789 checksumIn += currentLine_[i]; 7790 return true; 7791 } 7792 7793 /** 7794 * Adjust the input checksum for deleted chars. 7795 * This is called as an assert so it for is debug config only 7796 */ 7797 bool ASFormatter::adjustChecksumIn(int adjustment) 7798 { 7799 checksumIn += adjustment; 7800 return true; 7801 } 7802 7803 /** 7804 * get the value of checksumIn for unit testing 7805 * 7806 * @return checksumIn. 7807 */ 7808 size_t ASFormatter::getChecksumIn() const 7809 { 7810 return checksumIn; 7811 } 7812 7813 /** 7814 * Compute the output checksum. 7815 * This is called as an assert so it is for debug config only 7816 */ 7817 bool ASFormatter::computeChecksumOut(const string& beautifiedLine) 7818 { 7819 for (size_t i = 0; i < beautifiedLine.length(); i++) 7820 if (!isWhiteSpace(beautifiedLine[i])) 7821 checksumOut += beautifiedLine[i]; 7822 return true; 7823 } 7824 7825 /** 7826 * Return isLineReady for the final check at end of file. 7827 */ 7828 bool ASFormatter::getIsLineReady() const 7829 { 7830 return isLineReady; 7831 } 7832 7833 /** 7834 * get the value of checksumOut for unit testing 7835 * 7836 * @return checksumOut. 7837 */ 7838 size_t ASFormatter::getChecksumOut() const 7839 { 7840 return checksumOut; 7841 } 7842 7843 /** 7844 * Return the difference in checksums. 7845 * If zero all is okay. 7846 */ 7847 int ASFormatter::getChecksumDiff() const 7848 { 7849 return checksumOut - checksumIn; 7850 } 7851 7852 // for unit testing 7853 int ASFormatter::getFormatterFileType() const 7854 { 7855 return formatterFileType; 7856 } 7857 7858 // Check if an operator follows the next word. 7859 // The next word must be a legal name. 7860 const string* ASFormatter::getFollowingOperator() const 7861 { 7862 // find next word 7863 size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1); 7864 if (nextNum == string::npos) 7865 return nullptr; 7866 7867 if (!isLegalNameChar(currentLine[nextNum])) 7868 return nullptr; 7869 7870 // bypass next word and following spaces 7871 while (nextNum < currentLine.length()) 7872 { 7873 if (!isLegalNameChar(currentLine[nextNum]) 7874 && !isWhiteSpace(currentLine[nextNum])) 7875 break; 7876 nextNum++; 7877 } 7878 7879 if (nextNum >= currentLine.length() 7880 || !isCharPotentialOperator(currentLine[nextNum]) 7881 || currentLine[nextNum] == '/') // comment 7882 return nullptr; 7883 7884 const string* newOperator = ASBase::findOperator(currentLine, nextNum, operators); 7885 return newOperator; 7886 } 7887 7888 // Check following data to determine if the current character is an array operator. 7889 bool ASFormatter::isArrayOperator() const 7890 { 7891 assert(currentChar == '*' || currentChar == '&' || currentChar == '^'); 7892 assert(isBraceType(braceTypeStack->back(), ARRAY_TYPE)); 7893 7894 // find next word 7895 size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1); 7896 if (nextNum == string::npos) 7897 return false; 7898 7899 if (!isLegalNameChar(currentLine[nextNum])) 7900 return false; 7901 7902 // bypass next word and following spaces 7903 while (nextNum < currentLine.length()) 7904 { 7905 if (!isLegalNameChar(currentLine[nextNum]) 7906 && !isWhiteSpace(currentLine[nextNum])) 7907 break; 7908 nextNum++; 7909 } 7910 7911 // check for characters that indicate an operator 7912 if (currentLine[nextNum] == ',' 7913 || currentLine[nextNum] == '}' 7914 || currentLine[nextNum] == ')' 7915 || currentLine[nextNum] == '(') 7916 return true; 7917 return false; 7918 } 7919 7920 // Reset the flags that indicate various statement information. 7921 void ASFormatter::resetEndOfStatement() 7922 { 7923 foundQuestionMark = false; 7924 foundNamespaceHeader = false; 7925 foundClassHeader = false; 7926 foundStructHeader = false; 7927 foundInterfaceHeader = false; 7928 foundPreDefinitionHeader = false; 7929 foundPreCommandHeader = false; 7930 foundPreCommandMacro = false; 7931 foundTrailingReturnType = false; 7932 foundCastOperator = false; 7933 isInPotentialCalculation = false; 7934 isSharpAccessor = false; 7935 isSharpDelegate = false; 7936 isInObjCMethodDefinition = false; 7937 isImmediatelyPostObjCMethodPrefix = false; 7938 isInObjCReturnType = false; 7939 isInObjCParam = false; 7940 isInObjCInterface = false; 7941 isInObjCSelector = false; 7942 isInEnum = false; 7943 isInExternC = false; 7944 elseHeaderFollowsComments = false; 7945 returnTypeChecked = false; 7946 nonInStatementBrace = 0; 7947 while (!questionMarkStack->empty()) 7948 questionMarkStack->pop_back(); 7949 } 7950 7951 // Find the colon alignment for Objective-C method definitions and method calls. 7952 int ASFormatter::findObjCColonAlignment() const 7953 { 7954 assert(currentChar == '+' || currentChar == '-' || currentChar == '['); 7955 assert(getAlignMethodColon()); 7956 7957 bool isFirstLine = true; 7958 bool haveFirstColon = false; 7959 bool foundMethodColon = false; 7960 bool isInComment_ = false; 7961 bool isInQuote_ = false; 7962 bool haveTernary = false; 7963 char quoteChar_ = ' '; 7964 int sqBracketCount = 0; 7965 int colonAdjust = 0; 7966 int colonAlign = 0; 7967 string nextLine_ = currentLine; 7968 ASPeekStream stream(sourceIterator); 7969 7970 // peek next line 7971 while (sourceIterator->hasMoreLines() || isFirstLine) 7972 { 7973 if (!isFirstLine) 7974 nextLine_ = stream.peekNextLine(); 7975 // parse the line 7976 haveFirstColon = false; 7977 nextLine_ = ASBeautifier::trim(nextLine_); 7978 for (size_t i = 0; i < nextLine_.length(); i++) 7979 { 7980 if (isWhiteSpace(nextLine_[i])) 7981 continue; 7982 if (nextLine_.compare(i, 2, "/*") == 0) 7983 isInComment_ = true; 7984 if (isInComment_) 7985 { 7986 if (nextLine_.compare(i, 2, "*/") == 0) 7987 { 7988 isInComment_ = false; 7989 ++i; 7990 } 7991 continue; 7992 } 7993 if (nextLine_[i] == '\\') 7994 { 7995 ++i; 7996 continue; 7997 } 7998 if (isInQuote_) 7999 { 8000 if (nextLine_[i] == quoteChar_) 8001 isInQuote_ = false; 8002 continue; 8003 } 8004 8005 if (nextLine_[i] == '"' 8006 || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i))) 8007 { 8008 isInQuote_ = true; 8009 quoteChar_ = nextLine_[i]; 8010 continue; 8011 } 8012 if (nextLine_.compare(i, 2, "//") == 0) 8013 { 8014 i = nextLine_.length(); 8015 continue; 8016 } 8017 // process the current char 8018 if ((nextLine_[i] == '{' && (currentChar == '-' || currentChar == '+')) 8019 || nextLine_[i] == ';') 8020 goto EndOfWhileLoop; // end of method definition 8021 if (nextLine_[i] == ']') 8022 { 8023 --sqBracketCount; 8024 if (sqBracketCount == 0) 8025 goto EndOfWhileLoop; // end of method call 8026 } 8027 if (nextLine_[i] == '[') 8028 ++sqBracketCount; 8029 if (isFirstLine) // colon align does not include the first line 8030 continue; 8031 if (sqBracketCount > 1) 8032 continue; 8033 if (haveFirstColon) // multiple colons per line 8034 continue; 8035 if (nextLine_[i] == '?') 8036 { 8037 haveTernary = true; 8038 continue; 8039 } 8040 // compute colon adjustment 8041 if (nextLine_[i] == ':') 8042 { 8043 if (haveTernary) 8044 { 8045 haveTernary = false; 8046 continue; 8047 } 8048 haveFirstColon = true; 8049 foundMethodColon = true; 8050 if (shouldPadMethodColon) 8051 { 8052 int spacesStart; 8053 for (spacesStart = i; spacesStart > 0; spacesStart--) 8054 if (!isWhiteSpace(nextLine_[spacesStart - 1])) 8055 break; 8056 int spaces = i - spacesStart; 8057 if (objCColonPadMode == COLON_PAD_ALL || objCColonPadMode == COLON_PAD_BEFORE) 8058 colonAdjust = 1 - spaces; 8059 else if (objCColonPadMode == COLON_PAD_NONE || objCColonPadMode == COLON_PAD_AFTER) 8060 colonAdjust = 0 - spaces; 8061 } 8062 // compute alignment 8063 int colonPosition = i + colonAdjust; 8064 if (colonPosition > colonAlign) 8065 colonAlign = colonPosition; 8066 } 8067 } // end of for loop 8068 isFirstLine = false; 8069 } // end of while loop 8070 EndOfWhileLoop: 8071 if (!foundMethodColon) 8072 colonAlign = -1; 8073 return colonAlign; 8074 } 8075 8076 // pad an Objective-C method colon 8077 void ASFormatter::padObjCMethodColon() 8078 { 8079 assert(currentChar == ':'); 8080 int commentAdjust = 0; 8081 char nextChar = peekNextChar(); 8082 if (objCColonPadMode == COLON_PAD_NONE 8083 || objCColonPadMode == COLON_PAD_AFTER 8084 || nextChar == ')') 8085 { 8086 // remove spaces before 8087 for (int i = formattedLine.length() - 1; (i > -1) && isWhiteSpace(formattedLine[i]); i--) 8088 { 8089 formattedLine.erase(i); 8090 --commentAdjust; 8091 } 8092 } 8093 else 8094 { 8095 // pad space before 8096 for (int i = formattedLine.length() - 1; (i > 0) && isWhiteSpace(formattedLine[i]); i--) 8097 if (isWhiteSpace(formattedLine[i - 1])) 8098 { 8099 formattedLine.erase(i); 8100 --commentAdjust; 8101 } 8102 if (formattedLine.length() > 0) 8103 { 8104 appendSpacePad(); 8105 formattedLine.back() = ' '; // convert any tab to space 8106 } 8107 } 8108 if (objCColonPadMode == COLON_PAD_NONE 8109 || objCColonPadMode == COLON_PAD_BEFORE 8110 || nextChar == ')') 8111 { 8112 // remove spaces after 8113 size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1); 8114 if (nextText == string::npos) 8115 nextText = currentLine.length(); 8116 int spaces = nextText - charNum - 1; 8117 if (spaces > 0) 8118 { 8119 // do not use goForward here 8120 currentLine.erase(charNum + 1, spaces); 8121 spacePadNum -= spaces; 8122 } 8123 } 8124 else 8125 { 8126 // pad space after 8127 size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1); 8128 if (nextText == string::npos) 8129 nextText = currentLine.length(); 8130 int spaces = nextText - charNum - 1; 8131 if (spaces == 0) 8132 { 8133 currentLine.insert(charNum + 1, 1, ' '); 8134 spacePadNum += 1; 8135 } 8136 else if (spaces > 1) 8137 { 8138 // do not use goForward here 8139 currentLine.erase(charNum + 1, spaces - 1); 8140 currentLine[charNum + 1] = ' '; // convert any tab to space 8141 spacePadNum -= spaces - 1; 8142 } 8143 } 8144 spacePadNum += commentAdjust; 8145 } 8146 8147 // Remove the leading '*' from a comment line and indent to the next tab. 8148 void ASFormatter::stripCommentPrefix() 8149 { 8150 int firstChar = formattedLine.find_first_not_of(" \t"); 8151 if (firstChar < 0) 8152 return; 8153 8154 if (isInCommentStartLine) 8155 { 8156 // comment opener must begin the line 8157 if (formattedLine.compare(firstChar, 2, "/*") != 0) 8158 return; 8159 int commentOpener = firstChar; 8160 // ignore single line comments 8161 int commentEnd = formattedLine.find("*/", firstChar + 2); 8162 if (commentEnd != -1) 8163 return; 8164 // first char after the comment opener must be at least one indent 8165 int followingText = formattedLine.find_first_not_of(" \t", commentOpener + 2); 8166 if (followingText < 0) 8167 return; 8168 if (formattedLine[followingText] == '*' || formattedLine[followingText] == '!') 8169 followingText = formattedLine.find_first_not_of(" \t", followingText + 1); 8170 if (followingText < 0) 8171 return; 8172 if (formattedLine[followingText] == '*') 8173 return; 8174 int indentLen = getIndentLength(); 8175 int followingTextIndent = followingText - commentOpener; 8176 if (followingTextIndent < indentLen) 8177 { 8178 string stringToInsert(indentLen - followingTextIndent, ' '); 8179 formattedLine.insert(followingText, stringToInsert); 8180 } 8181 return; 8182 } 8183 // comment body including the closer 8184 if (formattedLine[firstChar] == '*') 8185 { 8186 if (formattedLine.compare(firstChar, 2, "*/") == 0) 8187 { 8188 // line starts with an end comment 8189 formattedLine = "*/"; 8190 } 8191 else 8192 { 8193 // build a new line with one indent 8194 int secondChar = formattedLine.find_first_not_of(" \t", firstChar + 1); 8195 if (secondChar < 0) 8196 { 8197 adjustChecksumIn(-'*'); 8198 formattedLine.erase(); 8199 return; 8200 } 8201 if (formattedLine[secondChar] == '*') 8202 return; 8203 // replace the leading '*' 8204 int indentLen = getIndentLength(); 8205 adjustChecksumIn(-'*'); 8206 // second char must be at least one indent 8207 if (formattedLine.substr(0, secondChar).find('\t') != string::npos) 8208 { 8209 formattedLine.erase(firstChar, 1); 8210 } 8211 else 8212 { 8213 int spacesToInsert = 0; 8214 if (secondChar >= indentLen) 8215 spacesToInsert = secondChar; 8216 else 8217 spacesToInsert = indentLen; 8218 formattedLine = string(spacesToInsert, ' ') + formattedLine.substr(secondChar); 8219 } 8220 // remove a trailing '*' 8221 int lastChar = formattedLine.find_last_not_of(" \t"); 8222 if (lastChar > -1 && formattedLine[lastChar] == '*') 8223 { 8224 adjustChecksumIn(-'*'); 8225 formattedLine[lastChar] = ' '; 8226 } 8227 } 8228 } 8229 else 8230 { 8231 // first char not a '*' 8232 // first char must be at least one indent 8233 if (formattedLine.substr(0, firstChar).find('\t') == string::npos) 8234 { 8235 int indentLen = getIndentLength(); 8236 if (firstChar < indentLen) 8237 { 8238 string stringToInsert(indentLen, ' '); 8239 formattedLine = stringToInsert + formattedLine.substr(firstChar); 8240 } 8241 } 8242 } 8243 } 8244 8245 } // end namespace astyle