File indexing completed on 2024-06-23 04:35:49
0001 // ASBeautifier.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 0014 //----------------------------------------------------------------------------- 0015 // astyle namespace 0016 //----------------------------------------------------------------------------- 0017 0018 namespace astyle { 0019 // 0020 // this must be global 0021 static int g_preprocessorCppExternCBrace; 0022 0023 //----------------------------------------------------------------------------- 0024 // ASBeautifier class 0025 //----------------------------------------------------------------------------- 0026 0027 /** 0028 * ASBeautifier's constructor 0029 * This constructor is called only once for each source file. 0030 * The cloned ASBeautifier objects are created with the copy constructor. 0031 */ 0032 ASBeautifier::ASBeautifier() 0033 { 0034 waitingBeautifierStack = nullptr; 0035 activeBeautifierStack = nullptr; 0036 waitingBeautifierStackLengthStack = nullptr; 0037 activeBeautifierStackLengthStack = nullptr; 0038 0039 headerStack = nullptr; 0040 tempStacks = nullptr; 0041 parenDepthStack = nullptr; 0042 blockStatementStack = nullptr; 0043 parenStatementStack = nullptr; 0044 braceBlockStateStack = nullptr; 0045 continuationIndentStack = nullptr; 0046 continuationIndentStackSizeStack = nullptr; 0047 parenIndentStack = nullptr; 0048 preprocIndentStack = nullptr; 0049 sourceIterator = nullptr; 0050 isModeManuallySet = false; 0051 shouldForceTabIndentation = false; 0052 setSpaceIndentation(4); 0053 setContinuationIndentation(1); 0054 setMinConditionalIndentOption(MINCOND_TWO); 0055 setMaxContinuationIndentLength(40); 0056 classInitializerIndents = 1; 0057 tabLength = 0; 0058 setClassIndent(false); 0059 setModifierIndent(false); 0060 setSwitchIndent(false); 0061 setCaseIndent(false); 0062 setBlockIndent(false); 0063 setBraceIndent(false); 0064 setBraceIndentVtk(false); 0065 setNamespaceIndent(false); 0066 setAfterParenIndent(false); 0067 setLabelIndent(false); 0068 setEmptyLineFill(false); 0069 setCStyle(); 0070 setPreprocDefineIndent(false); 0071 setPreprocConditionalIndent(false); 0072 setAlignMethodColon(false); 0073 0074 // initialize ASBeautifier member vectors 0075 beautifierFileType = 9; // reset to an invalid type 0076 headers = new vector<const string*>; 0077 nonParenHeaders = new vector<const string*>; 0078 assignmentOperators = new vector<const string*>; 0079 nonAssignmentOperators = new vector<const string*>; 0080 preBlockStatements = new vector<const string*>; 0081 preCommandHeaders = new vector<const string*>; 0082 indentableHeaders = new vector<const string*>; 0083 } 0084 0085 /** 0086 * ASBeautifier's copy constructor 0087 * Copy the vector objects to vectors in the new ASBeautifier 0088 * object so the new object can be destroyed without deleting 0089 * the vector objects in the copied vector. 0090 * This is the reason a copy constructor is needed. 0091 * 0092 * Must explicitly call the base class copy constructor. 0093 */ 0094 ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other) 0095 { 0096 // these don't need to copy the stack 0097 waitingBeautifierStack = nullptr; 0098 activeBeautifierStack = nullptr; 0099 waitingBeautifierStackLengthStack = nullptr; 0100 activeBeautifierStackLengthStack = nullptr; 0101 0102 // vector '=' operator performs a DEEP copy of all elements in the vector 0103 0104 headerStack = new vector<const string*>; 0105 *headerStack = *other.headerStack; 0106 0107 tempStacks = copyTempStacks(other); 0108 0109 parenDepthStack = new vector<int>; 0110 *parenDepthStack = *other.parenDepthStack; 0111 0112 blockStatementStack = new vector<bool>; 0113 *blockStatementStack = *other.blockStatementStack; 0114 0115 parenStatementStack = new vector<bool>; 0116 *parenStatementStack = *other.parenStatementStack; 0117 0118 braceBlockStateStack = new vector<bool>; 0119 *braceBlockStateStack = *other.braceBlockStateStack; 0120 0121 continuationIndentStack = new vector<int>; 0122 *continuationIndentStack = *other.continuationIndentStack; 0123 0124 continuationIndentStackSizeStack = new vector<int>; 0125 *continuationIndentStackSizeStack = *other.continuationIndentStackSizeStack; 0126 0127 parenIndentStack = new vector<int>; 0128 *parenIndentStack = *other.parenIndentStack; 0129 0130 preprocIndentStack = new vector<pair<int, int> >; 0131 *preprocIndentStack = *other.preprocIndentStack; 0132 0133 // Copy the pointers to vectors. 0134 // This is ok because the original ASBeautifier object 0135 // is not deleted until end of job. 0136 beautifierFileType = other.beautifierFileType; 0137 headers = other.headers; 0138 nonParenHeaders = other.nonParenHeaders; 0139 assignmentOperators = other.assignmentOperators; 0140 nonAssignmentOperators = other.nonAssignmentOperators; 0141 preBlockStatements = other.preBlockStatements; 0142 preCommandHeaders = other.preCommandHeaders; 0143 indentableHeaders = other.indentableHeaders; 0144 0145 // protected variables 0146 // variables set by ASFormatter 0147 // must also be updated in activeBeautifierStack 0148 inLineNumber = other.inLineNumber; 0149 runInIndentContinuation = other.runInIndentContinuation; 0150 nonInStatementBrace = other.nonInStatementBrace; 0151 objCColonAlignSubsequent = other.objCColonAlignSubsequent; 0152 lineCommentNoBeautify = other.lineCommentNoBeautify; 0153 isElseHeaderIndent = other.isElseHeaderIndent; 0154 isCaseHeaderCommentIndent = other.isCaseHeaderCommentIndent; 0155 isNonInStatementArray = other.isNonInStatementArray; 0156 isSharpAccessor = other.isSharpAccessor; 0157 isSharpDelegate = other.isSharpDelegate; 0158 isInExternC = other.isInExternC; 0159 isInBeautifySQL = other.isInBeautifySQL; 0160 isInIndentableStruct = other.isInIndentableStruct; 0161 isInIndentablePreproc = other.isInIndentablePreproc; 0162 0163 // private variables 0164 sourceIterator = other.sourceIterator; 0165 currentHeader = other.currentHeader; 0166 previousLastLineHeader = other.previousLastLineHeader; 0167 probationHeader = other.probationHeader; 0168 lastLineHeader = other.lastLineHeader; 0169 indentString = other.indentString; 0170 verbatimDelimiter = other.verbatimDelimiter; 0171 isInQuote = other.isInQuote; 0172 isInVerbatimQuote = other.isInVerbatimQuote; 0173 haveLineContinuationChar = other.haveLineContinuationChar; 0174 isInAsm = other.isInAsm; 0175 isInAsmOneLine = other.isInAsmOneLine; 0176 isInAsmBlock = other.isInAsmBlock; 0177 isInComment = other.isInComment; 0178 isInPreprocessorComment = other.isInPreprocessorComment; 0179 isInRunInComment = other.isInRunInComment; 0180 isInCase = other.isInCase; 0181 isInQuestion = other.isInQuestion; 0182 isContinuation = other.isContinuation; 0183 isInHeader = other.isInHeader; 0184 isInTemplate = other.isInTemplate; 0185 isInDefine = other.isInDefine; 0186 isInDefineDefinition = other.isInDefineDefinition; 0187 classIndent = other.classIndent; 0188 isIndentModeOff = other.isIndentModeOff; 0189 isInClassHeader = other.isInClassHeader; 0190 isInClassHeaderTab = other.isInClassHeaderTab; 0191 isInClassInitializer = other.isInClassInitializer; 0192 isInClass = other.isInClass; 0193 isInObjCMethodDefinition = other.isInObjCMethodDefinition; 0194 isInObjCMethodCall = other.isInObjCMethodCall; 0195 isInObjCMethodCallFirst = other.isInObjCMethodCallFirst; 0196 isImmediatelyPostObjCMethodDefinition = other.isImmediatelyPostObjCMethodDefinition; 0197 isImmediatelyPostObjCMethodCall = other.isImmediatelyPostObjCMethodCall; 0198 isInIndentablePreprocBlock = other.isInIndentablePreprocBlock; 0199 isInObjCInterface = other.isInObjCInterface; 0200 isInEnum = other.isInEnum; 0201 isInEnumTypeID = other.isInEnumTypeID; 0202 isInLet = other.isInLet; 0203 isInTrailingReturnType = other.isInTrailingReturnType; 0204 modifierIndent = other.modifierIndent; 0205 switchIndent = other.switchIndent; 0206 caseIndent = other.caseIndent; 0207 namespaceIndent = other.namespaceIndent; 0208 braceIndent = other.braceIndent; 0209 braceIndentVtk = other.braceIndentVtk; 0210 blockIndent = other.blockIndent; 0211 shouldIndentAfterParen = other.shouldIndentAfterParen; 0212 labelIndent = other.labelIndent; 0213 isInConditional = other.isInConditional; 0214 isModeManuallySet = other.isModeManuallySet; 0215 shouldForceTabIndentation = other.shouldForceTabIndentation; 0216 emptyLineFill = other.emptyLineFill; 0217 lineOpensWithLineComment = other.lineOpensWithLineComment; 0218 lineOpensWithComment = other.lineOpensWithComment; 0219 lineStartsInComment = other.lineStartsInComment; 0220 backslashEndsPrevLine = other.backslashEndsPrevLine; 0221 blockCommentNoIndent = other.blockCommentNoIndent; 0222 blockCommentNoBeautify = other.blockCommentNoBeautify; 0223 previousLineProbationTab = other.previousLineProbationTab; 0224 lineBeginsWithOpenBrace = other.lineBeginsWithOpenBrace; 0225 lineBeginsWithCloseBrace = other.lineBeginsWithCloseBrace; 0226 lineBeginsWithComma = other.lineBeginsWithComma; 0227 lineIsCommentOnly = other.lineIsCommentOnly; 0228 lineIsLineCommentOnly = other.lineIsLineCommentOnly; 0229 shouldIndentBracedLine = other.shouldIndentBracedLine; 0230 isInSwitch = other.isInSwitch; 0231 foundPreCommandHeader = other.foundPreCommandHeader; 0232 foundPreCommandMacro = other.foundPreCommandMacro; 0233 shouldAlignMethodColon = other.shouldAlignMethodColon; 0234 shouldIndentPreprocDefine = other.shouldIndentPreprocDefine; 0235 shouldIndentPreprocConditional = other.shouldIndentPreprocConditional; 0236 indentCount = other.indentCount; 0237 spaceIndentCount = other.spaceIndentCount; 0238 spaceIndentObjCMethodAlignment = other.spaceIndentObjCMethodAlignment; 0239 bracePosObjCMethodAlignment = other.bracePosObjCMethodAlignment; 0240 colonIndentObjCMethodAlignment = other.colonIndentObjCMethodAlignment; 0241 lineOpeningBlocksNum = other.lineOpeningBlocksNum; 0242 lineClosingBlocksNum = other.lineClosingBlocksNum; 0243 fileType = other.fileType; 0244 minConditionalOption = other.minConditionalOption; 0245 minConditionalIndent = other.minConditionalIndent; 0246 parenDepth = other.parenDepth; 0247 indentLength = other.indentLength; 0248 tabLength = other.tabLength; 0249 continuationIndent = other.continuationIndent; 0250 blockTabCount = other.blockTabCount; 0251 maxContinuationIndent = other.maxContinuationIndent; 0252 classInitializerIndents = other.classInitializerIndents; 0253 templateDepth = other.templateDepth; 0254 squareBracketCount = other.squareBracketCount; 0255 prevFinalLineSpaceIndentCount = other.prevFinalLineSpaceIndentCount; 0256 prevFinalLineIndentCount = other.prevFinalLineIndentCount; 0257 defineIndentCount = other.defineIndentCount; 0258 preprocBlockIndent = other.preprocBlockIndent; 0259 quoteChar = other.quoteChar; 0260 prevNonSpaceCh = other.prevNonSpaceCh; 0261 currentNonSpaceCh = other.currentNonSpaceCh; 0262 currentNonLegalCh = other.currentNonLegalCh; 0263 prevNonLegalCh = other.prevNonLegalCh; 0264 } 0265 0266 /** 0267 * ASBeautifier's destructor 0268 */ 0269 ASBeautifier::~ASBeautifier() 0270 { 0271 deleteBeautifierContainer(waitingBeautifierStack); 0272 deleteBeautifierContainer(activeBeautifierStack); 0273 deleteContainer(waitingBeautifierStackLengthStack); 0274 deleteContainer(activeBeautifierStackLengthStack); 0275 deleteContainer(headerStack); 0276 deleteTempStacksContainer(tempStacks); 0277 deleteContainer(parenDepthStack); 0278 deleteContainer(blockStatementStack); 0279 deleteContainer(parenStatementStack); 0280 deleteContainer(braceBlockStateStack); 0281 deleteContainer(continuationIndentStack); 0282 deleteContainer(continuationIndentStackSizeStack); 0283 deleteContainer(parenIndentStack); 0284 deleteContainer(preprocIndentStack); 0285 } 0286 0287 /** 0288 * initialize the ASBeautifier. 0289 * 0290 * This init() should be called every time a ABeautifier object is to start 0291 * beautifying a NEW source file. 0292 * It is called only when a new ASFormatter object is created. 0293 * init() receives a pointer to a ASSourceIterator object that will be 0294 * used to iterate through the source code. 0295 * 0296 * @param iter a pointer to the ASSourceIterator or ASStreamIterator object. 0297 */ 0298 void ASBeautifier::init(ASSourceIterator* iter) 0299 { 0300 sourceIterator = iter; 0301 initVectors(); 0302 ASBase::init(getFileType()); 0303 g_preprocessorCppExternCBrace = 0; 0304 0305 initContainer(waitingBeautifierStack, new vector<ASBeautifier*>); 0306 initContainer(activeBeautifierStack, new vector<ASBeautifier*>); 0307 0308 initContainer(waitingBeautifierStackLengthStack, new vector<int>); 0309 initContainer(activeBeautifierStackLengthStack, new vector<int>); 0310 0311 initContainer(headerStack, new vector<const string*>); 0312 0313 initTempStacksContainer(tempStacks, new vector<vector<const string*>*>); 0314 tempStacks->emplace_back(new vector<const string*>); 0315 0316 initContainer(parenDepthStack, new vector<int>); 0317 initContainer(blockStatementStack, new vector<bool>); 0318 initContainer(parenStatementStack, new vector<bool>); 0319 initContainer(braceBlockStateStack, new vector<bool>); 0320 braceBlockStateStack->push_back(true); 0321 initContainer(continuationIndentStack, new vector<int>); 0322 initContainer(continuationIndentStackSizeStack, new vector<int>); 0323 continuationIndentStackSizeStack->emplace_back(0); 0324 initContainer(parenIndentStack, new vector<int>); 0325 initContainer(preprocIndentStack, new vector<pair<int, int> >); 0326 0327 previousLastLineHeader = nullptr; 0328 currentHeader = nullptr; 0329 0330 isInQuote = false; 0331 isInVerbatimQuote = false; 0332 haveLineContinuationChar = false; 0333 isInAsm = false; 0334 isInAsmOneLine = false; 0335 isInAsmBlock = false; 0336 isInComment = false; 0337 isInPreprocessorComment = false; 0338 isInRunInComment = false; 0339 isContinuation = false; 0340 isInCase = false; 0341 isInQuestion = false; 0342 isIndentModeOff = false; 0343 isInClassHeader = false; 0344 isInClassHeaderTab = false; 0345 isInClassInitializer = false; 0346 isInClass = false; 0347 isInObjCMethodDefinition = false; 0348 isInObjCMethodCall = false; 0349 isInObjCMethodCallFirst = false; 0350 isImmediatelyPostObjCMethodDefinition = false; 0351 isImmediatelyPostObjCMethodCall = false; 0352 isInIndentablePreprocBlock = false; 0353 isInObjCInterface = false; 0354 isInEnum = false; 0355 isInEnumTypeID = false; 0356 isInLet = false; 0357 isInHeader = false; 0358 isInTemplate = false; 0359 isInConditional = false; 0360 isInTrailingReturnType = false; 0361 0362 indentCount = 0; 0363 spaceIndentCount = 0; 0364 spaceIndentObjCMethodAlignment = 0; 0365 bracePosObjCMethodAlignment = 0; 0366 colonIndentObjCMethodAlignment = 0; 0367 lineOpeningBlocksNum = 0; 0368 lineClosingBlocksNum = 0; 0369 templateDepth = 0; 0370 squareBracketCount = 0; 0371 parenDepth = 0; 0372 blockTabCount = 0; 0373 prevFinalLineSpaceIndentCount = 0; 0374 prevFinalLineIndentCount = 0; 0375 defineIndentCount = 0; 0376 preprocBlockIndent = 0; 0377 prevNonSpaceCh = '{'; 0378 currentNonSpaceCh = '{'; 0379 prevNonLegalCh = '{'; 0380 currentNonLegalCh = '{'; 0381 quoteChar = ' '; 0382 probationHeader = nullptr; 0383 lastLineHeader = nullptr; 0384 backslashEndsPrevLine = false; 0385 lineOpensWithLineComment = false; 0386 lineOpensWithComment = false; 0387 lineStartsInComment = false; 0388 isInDefine = false; 0389 isInDefineDefinition = false; 0390 lineCommentNoBeautify = false; 0391 isElseHeaderIndent = false; 0392 isCaseHeaderCommentIndent = false; 0393 blockCommentNoIndent = false; 0394 blockCommentNoBeautify = false; 0395 previousLineProbationTab = false; 0396 lineBeginsWithOpenBrace = false; 0397 lineBeginsWithCloseBrace = false; 0398 lineBeginsWithComma = false; 0399 lineIsCommentOnly = false; 0400 lineIsLineCommentOnly = false; 0401 shouldIndentBracedLine = true; 0402 isInSwitch = false; 0403 foundPreCommandHeader = false; 0404 foundPreCommandMacro = false; 0405 0406 isNonInStatementArray = false; 0407 isSharpAccessor = false; 0408 isSharpDelegate = false; 0409 isInExternC = false; 0410 isInBeautifySQL = false; 0411 isInIndentableStruct = false; 0412 isInIndentablePreproc = false; 0413 inLineNumber = 0; 0414 runInIndentContinuation = 0; 0415 nonInStatementBrace = 0; 0416 objCColonAlignSubsequent = 0; 0417 } 0418 0419 /* 0420 * initialize the vectors 0421 */ 0422 void ASBeautifier::initVectors() 0423 { 0424 if (fileType == beautifierFileType) // don't build unless necessary 0425 return; 0426 0427 beautifierFileType = fileType; 0428 0429 headers->clear(); 0430 nonParenHeaders->clear(); 0431 assignmentOperators->clear(); 0432 nonAssignmentOperators->clear(); 0433 preBlockStatements->clear(); 0434 preCommandHeaders->clear(); 0435 indentableHeaders->clear(); 0436 0437 ASResource::buildHeaders(headers, fileType, true); 0438 ASResource::buildNonParenHeaders(nonParenHeaders, fileType, true); 0439 ASResource::buildAssignmentOperators(assignmentOperators); 0440 ASResource::buildNonAssignmentOperators(nonAssignmentOperators); 0441 ASResource::buildPreBlockStatements(preBlockStatements, fileType); 0442 ASResource::buildPreCommandHeaders(preCommandHeaders, fileType); 0443 ASResource::buildIndentableHeaders(indentableHeaders); 0444 } 0445 0446 /** 0447 * set indentation style to C/C++. 0448 */ 0449 void ASBeautifier::setCStyle() 0450 { 0451 fileType = C_TYPE; 0452 } 0453 0454 /** 0455 * set indentation style to Java. 0456 */ 0457 void ASBeautifier::setJavaStyle() 0458 { 0459 fileType = JAVA_TYPE; 0460 } 0461 0462 /** 0463 * set indentation style to C#. 0464 */ 0465 void ASBeautifier::setSharpStyle() 0466 { 0467 fileType = SHARP_TYPE; 0468 } 0469 0470 /** 0471 * set mode manually set flag 0472 */ 0473 void ASBeautifier::setModeManuallySet(bool state) 0474 { 0475 isModeManuallySet = state; 0476 } 0477 0478 /** 0479 * set tabLength equal to indentLength. 0480 * This is done when tabLength is not explicitly set by 0481 * "indent=force-tab-x" 0482 * 0483 */ 0484 void ASBeautifier::setDefaultTabLength() 0485 { 0486 tabLength = indentLength; 0487 } 0488 0489 /** 0490 * indent using a different tab setting for indent=force-tab 0491 * 0492 * @param length number of spaces per tab. 0493 */ 0494 void ASBeautifier::setForceTabXIndentation(int length) 0495 { 0496 // set tabLength instead of indentLength 0497 indentString = "\t"; 0498 tabLength = length; 0499 shouldForceTabIndentation = true; 0500 } 0501 0502 /** 0503 * indent using one tab per indentation 0504 */ 0505 void ASBeautifier::setTabIndentation(int length, bool forceTabs) 0506 { 0507 indentString = "\t"; 0508 indentLength = length; 0509 shouldForceTabIndentation = forceTabs; 0510 } 0511 0512 /** 0513 * indent using a number of spaces per indentation. 0514 * 0515 * @param length number of spaces per indent. 0516 */ 0517 void ASBeautifier::setSpaceIndentation(int length) 0518 { 0519 indentString = string(length, ' '); 0520 indentLength = length; 0521 } 0522 0523 /** 0524 * indent continuation lines using a number of indents. 0525 * 0526 * @param indent number of indents per line. 0527 */ 0528 void ASBeautifier::setContinuationIndentation(int indent) 0529 { 0530 continuationIndent = indent; 0531 } 0532 0533 /** 0534 * set the maximum indentation between two lines in a multi-line statement. 0535 * 0536 * @param max maximum indentation length. 0537 */ 0538 void ASBeautifier::setMaxContinuationIndentLength(int max) 0539 { 0540 maxContinuationIndent = max; 0541 } 0542 0543 // retained for compatibility with release 2.06 0544 // "MaxInStatementIndent" has been changed to "MaxContinuationIndent" in 3.0 0545 // it is referenced only by the old "MaxInStatementIndent" options 0546 void ASBeautifier::setMaxInStatementIndentLength(int max) 0547 { 0548 setMaxContinuationIndentLength(max); 0549 } 0550 0551 /** 0552 * set the minimum conditional indentation option. 0553 * 0554 * @param min minimal indentation option. 0555 */ 0556 void ASBeautifier::setMinConditionalIndentOption(int min) 0557 { 0558 minConditionalOption = min; 0559 } 0560 0561 /** 0562 * set minConditionalIndent from the minConditionalOption. 0563 */ 0564 void ASBeautifier::setMinConditionalIndentLength() 0565 { 0566 if (minConditionalOption == MINCOND_ZERO) 0567 minConditionalIndent = 0; 0568 else if (minConditionalOption == MINCOND_ONE) 0569 minConditionalIndent = indentLength; 0570 else if (minConditionalOption == MINCOND_ONEHALF) 0571 minConditionalIndent = indentLength / 2; 0572 // minConditionalOption = INDENT_TWO 0573 else 0574 minConditionalIndent = indentLength * 2; 0575 } 0576 0577 /** 0578 * set the state of the brace indent option. If true, braces will 0579 * be indented one additional indent. 0580 * 0581 * @param state state of option. 0582 */ 0583 void ASBeautifier::setBraceIndent(bool state) 0584 { 0585 braceIndent = state; 0586 } 0587 0588 /** 0589 * set the state of the brace indent VTK option. If true, braces will 0590 * be indented one additional indent, except for the opening brace. 0591 * 0592 * @param state state of option. 0593 */ 0594 void ASBeautifier::setBraceIndentVtk(bool state) 0595 { 0596 // need to set both of these 0597 setBraceIndent(state); 0598 braceIndentVtk = state; 0599 } 0600 0601 /** 0602 * set the state of the block indentation option. If true, entire blocks 0603 * will be indented one additional indent, similar to the GNU indent style. 0604 * 0605 * @param state state of option. 0606 */ 0607 void ASBeautifier::setBlockIndent(bool state) 0608 { 0609 blockIndent = state; 0610 } 0611 0612 /** 0613 * set the state of the class indentation option. If true, C++ class 0614 * definitions will be indented one additional indent. 0615 * 0616 * @param state state of option. 0617 */ 0618 void ASBeautifier::setClassIndent(bool state) 0619 { 0620 classIndent = state; 0621 } 0622 0623 /** 0624 * set the state of the modifier indentation option. If true, C++ class 0625 * access modifiers will be indented one-half an indent. 0626 * 0627 * @param state state of option. 0628 */ 0629 void ASBeautifier::setModifierIndent(bool state) 0630 { 0631 modifierIndent = state; 0632 } 0633 0634 /** 0635 * set the state of the switch indentation option. If true, blocks of 'switch' 0636 * statements will be indented one additional indent. 0637 * 0638 * @param state state of option. 0639 */ 0640 void ASBeautifier::setSwitchIndent(bool state) 0641 { 0642 switchIndent = state; 0643 } 0644 0645 /** 0646 * set the state of the case indentation option. If true, lines of 'case' 0647 * statements will be indented one additional indent. 0648 * 0649 * @param state state of option. 0650 */ 0651 void ASBeautifier::setCaseIndent(bool state) 0652 { 0653 caseIndent = state; 0654 } 0655 0656 /** 0657 * set the state of the namespace indentation option. 0658 * If true, blocks of 'namespace' statements will be indented one 0659 * additional indent. Otherwise, NO indentation will be added. 0660 * 0661 * @param state state of option. 0662 */ 0663 void ASBeautifier::setNamespaceIndent(bool state) 0664 { 0665 namespaceIndent = state; 0666 } 0667 0668 /** 0669 * set the state of the indent after parens option. 0670 * 0671 * @param state state of option. 0672 */ 0673 void ASBeautifier::setAfterParenIndent(bool state) 0674 { 0675 shouldIndentAfterParen = state; 0676 } 0677 0678 /** 0679 * set the state of the label indentation option. 0680 * If true, labels will be indented one indent LESS than the 0681 * current indentation level. 0682 * If false, labels will be flushed to the left with NO 0683 * indent at all. 0684 * 0685 * @param state state of option. 0686 */ 0687 void ASBeautifier::setLabelIndent(bool state) 0688 { 0689 labelIndent = state; 0690 } 0691 0692 /** 0693 * set the state of the preprocessor indentation option. 0694 * If true, multi-line #define statements will be indented. 0695 * 0696 * @param state state of option. 0697 */ 0698 void ASBeautifier::setPreprocDefineIndent(bool state) 0699 { 0700 shouldIndentPreprocDefine = state; 0701 } 0702 0703 void ASBeautifier::setPreprocConditionalIndent(bool state) 0704 { 0705 shouldIndentPreprocConditional = state; 0706 } 0707 0708 /** 0709 * set the state of the empty line fill option. 0710 * If true, empty lines will be filled with the whitespace. 0711 * of their previous lines. 0712 * If false, these lines will remain empty. 0713 * 0714 * @param state state of option. 0715 */ 0716 void ASBeautifier::setEmptyLineFill(bool state) 0717 { 0718 emptyLineFill = state; 0719 } 0720 0721 void ASBeautifier::setAlignMethodColon(bool state) 0722 { 0723 shouldAlignMethodColon = state; 0724 } 0725 0726 /** 0727 * get the file type. 0728 */ 0729 int ASBeautifier::getFileType() const 0730 { 0731 return fileType; 0732 } 0733 0734 /** 0735 * get the number of spaces per indent 0736 * 0737 * @return value of indentLength option. 0738 */ 0739 int ASBeautifier::getIndentLength() const 0740 { 0741 return indentLength; 0742 } 0743 0744 /** 0745 * get the char used for indentation, space or tab 0746 * 0747 * @return the char used for indentation. 0748 */ 0749 string ASBeautifier::getIndentString() const 0750 { 0751 return indentString; 0752 } 0753 0754 /** 0755 * get mode manually set flag 0756 */ 0757 bool ASBeautifier::getModeManuallySet() const 0758 { 0759 return isModeManuallySet; 0760 } 0761 0762 /** 0763 * get the state of the force tab indentation option. 0764 * 0765 * @return state of force tab indentation. 0766 */ 0767 bool ASBeautifier::getForceTabIndentation() const 0768 { 0769 return shouldForceTabIndentation; 0770 } 0771 0772 /** 0773 * Get the state of the Objective-C align method colon option. 0774 * 0775 * @return state of shouldAlignMethodColon option. 0776 */ 0777 bool ASBeautifier::getAlignMethodColon() const 0778 { 0779 return shouldAlignMethodColon; 0780 } 0781 0782 /** 0783 * get the state of the block indentation option. 0784 * 0785 * @return state of blockIndent option. 0786 */ 0787 bool ASBeautifier::getBlockIndent() const 0788 { 0789 return blockIndent; 0790 } 0791 0792 /** 0793 * get the state of the brace indentation option. 0794 * 0795 * @return state of braceIndent option. 0796 */ 0797 bool ASBeautifier::getBraceIndent() const 0798 { 0799 return braceIndent; 0800 } 0801 0802 /** 0803 * Get the state of the namespace indentation option. If true, blocks 0804 * of the 'namespace' statement will be indented one additional indent. 0805 * 0806 * @return state of namespaceIndent option. 0807 */ 0808 bool ASBeautifier::getNamespaceIndent() const 0809 { 0810 return namespaceIndent; 0811 } 0812 0813 /** 0814 * Get the state of the class indentation option. If true, blocks of 0815 * the 'class' statement will be indented one additional indent. 0816 * 0817 * @return state of classIndent option. 0818 */ 0819 bool ASBeautifier::getClassIndent() const 0820 { 0821 return classIndent; 0822 } 0823 0824 /** 0825 * Get the state of the class access modifier indentation option. 0826 * If true, the class access modifiers will be indented one-half indent. 0827 * 0828 * @return state of modifierIndent option. 0829 */ 0830 bool ASBeautifier::getModifierIndent() const 0831 { 0832 return modifierIndent; 0833 } 0834 0835 /** 0836 * get the state of the switch indentation option. If true, blocks of 0837 * the 'switch' statement will be indented one additional indent. 0838 * 0839 * @return state of switchIndent option. 0840 */ 0841 bool ASBeautifier::getSwitchIndent() const 0842 { 0843 return switchIndent; 0844 } 0845 0846 /** 0847 * get the state of the case indentation option. If true, lines of 'case' 0848 * statements will be indented one additional indent. 0849 * 0850 * @return state of caseIndent option. 0851 */ 0852 bool ASBeautifier::getCaseIndent() const 0853 { 0854 return caseIndent; 0855 } 0856 0857 /** 0858 * get the state of the empty line fill option. 0859 * If true, empty lines will be filled with the whitespace. 0860 * of their previous lines. 0861 * If false, these lines will remain empty. 0862 * 0863 * @return state of emptyLineFill option. 0864 */ 0865 bool ASBeautifier::getEmptyLineFill() const 0866 { 0867 return emptyLineFill; 0868 } 0869 0870 /** 0871 * get the state of the preprocessor indentation option. 0872 * If true, preprocessor "define" lines will be indented. 0873 * If false, preprocessor "define" lines will be unchanged. 0874 * 0875 * @return state of shouldIndentPreprocDefine option. 0876 */ 0877 bool ASBeautifier::getPreprocDefineIndent() const 0878 { 0879 return shouldIndentPreprocDefine; 0880 } 0881 0882 /** 0883 * get the length of the tab indentation option. 0884 * 0885 * @return length of tab indent option. 0886 */ 0887 int ASBeautifier::getTabLength() const 0888 { 0889 return tabLength; 0890 } 0891 0892 /** 0893 * beautify a line of source code. 0894 * every line of source code in a source code file should be sent 0895 * one after the other to the beautify method. 0896 * 0897 * @return the indented line. 0898 * @param originalLine the original unindented line. 0899 */ 0900 string ASBeautifier::beautify(const string& originalLine) 0901 { 0902 string line; 0903 bool isInQuoteContinuation = isInVerbatimQuote || haveLineContinuationChar; 0904 0905 currentHeader = nullptr; 0906 lastLineHeader = nullptr; 0907 blockCommentNoBeautify = blockCommentNoIndent; 0908 isInClass = false; 0909 isInSwitch = false; 0910 lineBeginsWithOpenBrace = false; 0911 lineBeginsWithCloseBrace = false; 0912 lineBeginsWithComma = false; 0913 lineIsCommentOnly = false; 0914 lineIsLineCommentOnly = false; 0915 shouldIndentBracedLine = true; 0916 isInAsmOneLine = false; 0917 lineOpensWithLineComment = false; 0918 lineOpensWithComment = false; 0919 lineStartsInComment = isInComment; 0920 previousLineProbationTab = false; 0921 lineOpeningBlocksNum = 0; 0922 lineClosingBlocksNum = 0; 0923 if (isImmediatelyPostObjCMethodDefinition) 0924 clearObjCMethodDefinitionAlignment(); 0925 if (isImmediatelyPostObjCMethodCall) 0926 { 0927 isImmediatelyPostObjCMethodCall = false; 0928 isInObjCMethodCall = false; 0929 objCColonAlignSubsequent = 0; 0930 } 0931 0932 // handle and remove white spaces around the line: 0933 // If not in comment, first find out size of white space before line, 0934 // so that possible comments starting in the line continue in 0935 // relation to the preliminary white-space. 0936 if (isInQuoteContinuation) 0937 { 0938 // trim a single space added by ASFormatter, otherwise leave it alone 0939 if (!(originalLine.length() == 1 && originalLine[0] == ' ')) 0940 line = originalLine; 0941 } 0942 else if (isInComment || isInBeautifySQL) 0943 { 0944 // trim the end of comment and SQL lines 0945 line = originalLine; 0946 size_t trimEnd = line.find_last_not_of(" \t"); 0947 if (trimEnd == string::npos) 0948 trimEnd = 0; 0949 else 0950 trimEnd++; 0951 if (trimEnd < line.length()) 0952 line.erase(trimEnd); 0953 // does a brace open the line 0954 size_t firstChar = line.find_first_not_of(" \t"); 0955 if (firstChar != string::npos) 0956 { 0957 if (line[firstChar] == '{') 0958 lineBeginsWithOpenBrace = true; 0959 else if (line[firstChar] == '}') 0960 lineBeginsWithCloseBrace = true; 0961 else if (line[firstChar] == ',') 0962 lineBeginsWithComma = true; 0963 } 0964 } 0965 else 0966 { 0967 line = trim(originalLine); 0968 if (line.length() > 0) 0969 { 0970 if (line[0] == '{') 0971 lineBeginsWithOpenBrace = true; 0972 else if (line[0] == '}') 0973 lineBeginsWithCloseBrace = true; 0974 else if (line[0] == ',') 0975 lineBeginsWithComma = true; 0976 else if (line.compare(0, 2, "//") == 0) 0977 lineIsLineCommentOnly = true; 0978 else if (line.compare(0, 2, "/*") == 0) 0979 { 0980 if (line.find("*/", 2) != string::npos) 0981 lineIsCommentOnly = true; 0982 } 0983 } 0984 0985 isInRunInComment = false; 0986 size_t j = line.find_first_not_of(" \t{"); 0987 if (j != string::npos && line.compare(j, 2, "//") == 0) 0988 lineOpensWithLineComment = true; 0989 if (j != string::npos && line.compare(j, 2, "/*") == 0) 0990 { 0991 lineOpensWithComment = true; 0992 size_t k = line.find_first_not_of(" \t"); 0993 if (k != string::npos && line.compare(k, 1, "{") == 0) 0994 isInRunInComment = true; 0995 } 0996 } 0997 0998 // When indent is OFF the lines must still be processed by ASBeautifier. 0999 // Otherwise the lines immediately following may not be indented correctly. 1000 if ((lineIsLineCommentOnly || lineIsCommentOnly) 1001 && line.find("*INDENT-OFF*", 0) != string::npos) 1002 isIndentModeOff = true; 1003 1004 if (line.length() == 0) 1005 { 1006 if (backslashEndsPrevLine) 1007 { 1008 backslashEndsPrevLine = false; 1009 // check if this line ends a multi-line #define 1010 // if so, remove the #define's cloned beautifier from the active 1011 // beautifier stack and delete it. 1012 if (isInDefineDefinition && !isInDefine) 1013 { 1014 isInDefineDefinition = false; 1015 if (!activeBeautifierStack->empty()) 1016 { 1017 ASBeautifier* defineBeautifier = activeBeautifierStack->back(); 1018 activeBeautifierStack->pop_back(); 1019 delete defineBeautifier; 1020 } 1021 } 1022 } 1023 if (emptyLineFill && !isInQuoteContinuation) 1024 { 1025 if (isInIndentablePreprocBlock) 1026 return preLineWS(preprocBlockIndent, 0); 1027 if (!headerStack->empty() || isInEnum) 1028 return preLineWS(prevFinalLineIndentCount, prevFinalLineSpaceIndentCount); 1029 // must fall thru here 1030 } 1031 else 1032 return line; 1033 } 1034 1035 // handle preprocessor commands 1036 if (isInIndentablePreprocBlock 1037 && line.length() > 0 1038 && line[0] != '#') 1039 { 1040 string indentedLine; 1041 if (isInClassHeaderTab || isInClassInitializer) 1042 { 1043 // parsing is turned off in ASFormatter by indent-off 1044 // the originalLine will probably never be returned here 1045 indentedLine = preLineWS(prevFinalLineIndentCount, prevFinalLineSpaceIndentCount) + line; 1046 return getIndentedLineReturn(indentedLine, originalLine); 1047 } 1048 indentedLine = preLineWS(preprocBlockIndent, 0) + line; 1049 return getIndentedLineReturn(indentedLine, originalLine); 1050 } 1051 1052 if (!isInComment 1053 && !isInQuoteContinuation 1054 && line.length() > 0 1055 && ((line[0] == '#' && !isIndentedPreprocessor(line, 0)) 1056 || backslashEndsPrevLine)) 1057 { 1058 if (line[0] == '#' && !isInDefine) 1059 { 1060 string preproc = extractPreprocessorStatement(line); 1061 processPreprocessor(preproc, line); 1062 if (isInIndentablePreprocBlock || isInIndentablePreproc) 1063 { 1064 string indentedLine; 1065 if ((preproc.length() >= 2 && preproc.substr(0, 2) == "if")) // #if, #ifdef, #ifndef 1066 { 1067 indentedLine = preLineWS(preprocBlockIndent, 0) + line; 1068 preprocBlockIndent += 1; 1069 isInIndentablePreprocBlock = true; 1070 } 1071 else if (preproc == "else" || preproc == "elif") 1072 { 1073 indentedLine = preLineWS(preprocBlockIndent - 1, 0) + line; 1074 } 1075 else if (preproc == "endif") 1076 { 1077 preprocBlockIndent -= 1; 1078 indentedLine = preLineWS(preprocBlockIndent, 0) + line; 1079 if (preprocBlockIndent == 0) 1080 isInIndentablePreprocBlock = false; 1081 } 1082 else 1083 indentedLine = preLineWS(preprocBlockIndent, 0) + line; 1084 return getIndentedLineReturn(indentedLine, originalLine); 1085 } 1086 if (shouldIndentPreprocConditional && preproc.length() > 0) 1087 { 1088 string indentedLine; 1089 if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef 1090 { 1091 pair<int, int> entry; // indentCount, spaceIndentCount 1092 if (!isInDefine && activeBeautifierStack != nullptr && !activeBeautifierStack->empty()) 1093 entry = activeBeautifierStack->back()->computePreprocessorIndent(); 1094 else 1095 entry = computePreprocessorIndent(); 1096 preprocIndentStack->emplace_back(entry); 1097 indentedLine = preLineWS(preprocIndentStack->back().first, 1098 preprocIndentStack->back().second) + line; 1099 return getIndentedLineReturn(indentedLine, originalLine); 1100 } 1101 if (preproc == "else" || preproc == "elif") 1102 { 1103 if (!preprocIndentStack->empty()) // if no entry don't indent 1104 { 1105 indentedLine = preLineWS(preprocIndentStack->back().first, 1106 preprocIndentStack->back().second) + line; 1107 return getIndentedLineReturn(indentedLine, originalLine); 1108 } 1109 } 1110 else if (preproc == "endif") 1111 { 1112 if (!preprocIndentStack->empty()) // if no entry don't indent 1113 { 1114 indentedLine = preLineWS(preprocIndentStack->back().first, 1115 preprocIndentStack->back().second) + line; 1116 preprocIndentStack->pop_back(); 1117 return getIndentedLineReturn(indentedLine, originalLine); 1118 } 1119 } 1120 } 1121 } 1122 1123 // check if the last char is a backslash 1124 if (line.length() > 0) 1125 backslashEndsPrevLine = (line[line.length() - 1] == '\\'); 1126 // comments within the definition line can be continued without the backslash 1127 if (isInPreprocessorUnterminatedComment(line)) 1128 backslashEndsPrevLine = true; 1129 1130 // check if this line ends a multi-line #define 1131 // if so, use the #define's cloned beautifier for the line's indentation 1132 // and then remove it from the active beautifier stack and delete it. 1133 if (!backslashEndsPrevLine && isInDefineDefinition && !isInDefine) 1134 { 1135 isInDefineDefinition = false; 1136 // this could happen with invalid input 1137 if (activeBeautifierStack->empty()) 1138 return originalLine; 1139 ASBeautifier* defineBeautifier = activeBeautifierStack->back(); 1140 activeBeautifierStack->pop_back(); 1141 1142 string indentedLine = defineBeautifier->beautify(line); 1143 delete defineBeautifier; 1144 return getIndentedLineReturn(indentedLine, originalLine); 1145 } 1146 1147 // unless this is a multi-line #define, return this precompiler line as is. 1148 if (!isInDefine && !isInDefineDefinition) 1149 return originalLine; 1150 } 1151 1152 // if there exists any worker beautifier in the activeBeautifierStack, 1153 // then use it instead of me to indent the current line. 1154 // variables set by ASFormatter must be updated. 1155 if (!isInDefine && activeBeautifierStack != nullptr && !activeBeautifierStack->empty()) 1156 { 1157 activeBeautifierStack->back()->inLineNumber = inLineNumber; 1158 activeBeautifierStack->back()->runInIndentContinuation = runInIndentContinuation; 1159 activeBeautifierStack->back()->nonInStatementBrace = nonInStatementBrace; 1160 activeBeautifierStack->back()->objCColonAlignSubsequent = objCColonAlignSubsequent; 1161 activeBeautifierStack->back()->lineCommentNoBeautify = lineCommentNoBeautify; 1162 activeBeautifierStack->back()->isElseHeaderIndent = isElseHeaderIndent; 1163 activeBeautifierStack->back()->isCaseHeaderCommentIndent = isCaseHeaderCommentIndent; 1164 activeBeautifierStack->back()->isNonInStatementArray = isNonInStatementArray; 1165 activeBeautifierStack->back()->isSharpAccessor = isSharpAccessor; 1166 activeBeautifierStack->back()->isSharpDelegate = isSharpDelegate; 1167 activeBeautifierStack->back()->isInExternC = isInExternC; 1168 activeBeautifierStack->back()->isInBeautifySQL = isInBeautifySQL; 1169 activeBeautifierStack->back()->isInIndentableStruct = isInIndentableStruct; 1170 activeBeautifierStack->back()->isInIndentablePreproc = isInIndentablePreproc; 1171 // must return originalLine not the trimmed line 1172 return activeBeautifierStack->back()->beautify(originalLine); 1173 } 1174 1175 // Flag an indented header in case this line is a one-line block. 1176 // The header in the header stack will be deleted by a one-line block. 1177 bool isInExtraHeaderIndent = false; 1178 if (!headerStack->empty() 1179 && lineBeginsWithOpenBrace 1180 && (headerStack->back() != &AS_OPEN_BRACE 1181 || probationHeader != nullptr)) 1182 isInExtraHeaderIndent = true; 1183 1184 size_t iPrelim = headerStack->size(); 1185 1186 // calculate preliminary indentation based on headerStack and data from past lines 1187 computePreliminaryIndentation(); 1188 1189 // parse characters in the current line. 1190 parseCurrentLine(line); 1191 1192 // handle special cases of indentation 1193 adjustParsedLineIndentation(iPrelim, isInExtraHeaderIndent); 1194 1195 if (isInObjCMethodDefinition) 1196 adjustObjCMethodDefinitionIndentation(line); 1197 1198 if (isInObjCMethodCall) 1199 adjustObjCMethodCallIndentation(line); 1200 1201 if (isInDefine) 1202 { 1203 if (line.length() > 0 && line[0] == '#') 1204 { 1205 // the 'define' does not have to be attached to the '#' 1206 string preproc = trim(line.substr(1)); 1207 if (preproc.compare(0, 6, "define") == 0) 1208 { 1209 if (!continuationIndentStack->empty() 1210 && continuationIndentStack->back() > 0) 1211 { 1212 defineIndentCount = indentCount; 1213 } 1214 else 1215 { 1216 defineIndentCount = indentCount - 1; 1217 --indentCount; 1218 } 1219 } 1220 } 1221 1222 indentCount -= defineIndentCount; 1223 } 1224 1225 if (indentCount < 0) 1226 indentCount = 0; 1227 1228 if (lineCommentNoBeautify || blockCommentNoBeautify || isInQuoteContinuation) 1229 indentCount = spaceIndentCount = 0; 1230 1231 // finally, insert indentations into beginning of line 1232 1233 string indentedLine = preLineWS(indentCount, spaceIndentCount) + line; 1234 indentedLine = getIndentedLineReturn(indentedLine, originalLine); 1235 1236 prevFinalLineSpaceIndentCount = spaceIndentCount; 1237 prevFinalLineIndentCount = indentCount; 1238 1239 if (lastLineHeader != nullptr) 1240 previousLastLineHeader = lastLineHeader; 1241 1242 if ((lineIsLineCommentOnly || lineIsCommentOnly) 1243 && line.find("*INDENT-ON*", 0) != string::npos) 1244 isIndentModeOff = false; 1245 1246 return indentedLine; 1247 } 1248 1249 const string& ASBeautifier::getIndentedLineReturn(const string& newLine, const string& originalLine) const 1250 { 1251 if (isIndentModeOff) 1252 return originalLine; 1253 return newLine; 1254 } 1255 1256 string ASBeautifier::preLineWS(int lineIndentCount, int lineSpaceIndentCount) const 1257 { 1258 if (shouldForceTabIndentation) 1259 { 1260 if (tabLength != indentLength) 1261 { 1262 // adjust for different tab length 1263 int indentCountOrig = lineIndentCount; 1264 int spaceIndentCountOrig = lineSpaceIndentCount; 1265 lineIndentCount = ((indentCountOrig * indentLength) + spaceIndentCountOrig) / tabLength; 1266 lineSpaceIndentCount = ((indentCountOrig * indentLength) + spaceIndentCountOrig) % tabLength; 1267 } 1268 else 1269 { 1270 lineIndentCount += lineSpaceIndentCount / indentLength; 1271 lineSpaceIndentCount = lineSpaceIndentCount % indentLength; 1272 } 1273 } 1274 1275 string ws; 1276 for (int i = 0; i < lineIndentCount; i++) 1277 ws += indentString; 1278 while ((lineSpaceIndentCount--) > 0) 1279 ws += string(" "); 1280 return ws; 1281 } 1282 1283 /** 1284 * register a continuation indent. 1285 */ 1286 void ASBeautifier::registerContinuationIndent(const string& line, int i, int spaceIndentCount_, 1287 int tabIncrementIn, int minIndent, bool updateParenStack) 1288 { 1289 assert(i >= -1); 1290 int remainingCharNum = line.length() - i; 1291 int nextNonWSChar = getNextProgramCharDistance(line, i); 1292 1293 // if indent is around the last char in the line OR indent-after-paren is requested, 1294 // indent with the continuation indent 1295 if (nextNonWSChar == remainingCharNum || shouldIndentAfterParen) 1296 { 1297 int previousIndent = spaceIndentCount_; 1298 if (!continuationIndentStack->empty()) 1299 previousIndent = continuationIndentStack->back(); 1300 int currIndent = continuationIndent * indentLength + previousIndent; 1301 if (currIndent > maxContinuationIndent && line[i] != '{') 1302 currIndent = indentLength * 2 + spaceIndentCount_; 1303 continuationIndentStack->emplace_back(currIndent); 1304 if (updateParenStack) 1305 parenIndentStack->emplace_back(previousIndent); 1306 return; 1307 } 1308 1309 if (updateParenStack) 1310 { 1311 parenIndentStack->emplace_back(i + spaceIndentCount_ - runInIndentContinuation); 1312 if (parenIndentStack->back() < 0) 1313 parenIndentStack->back() = 0; 1314 } 1315 1316 int tabIncrement = tabIncrementIn; 1317 1318 // check for following tabs 1319 for (int j = i + 1; j < (i + nextNonWSChar); j++) 1320 { 1321 if (line[j] == '\t') 1322 tabIncrement += convertTabToSpaces(j, tabIncrement); 1323 } 1324 1325 int continuationIndentCount = i + nextNonWSChar + spaceIndentCount_ + tabIncrement; 1326 1327 // check for run-in statement 1328 if (i > 0 && line[0] == '{') 1329 continuationIndentCount -= indentLength; 1330 1331 if (continuationIndentCount < minIndent) 1332 continuationIndentCount = minIndent + spaceIndentCount_; 1333 1334 // this is not done for an in-statement array 1335 if (continuationIndentCount > maxContinuationIndent 1336 && !(prevNonLegalCh == '=' && currentNonLegalCh == '{')) 1337 continuationIndentCount = indentLength * 2 + spaceIndentCount_; 1338 1339 if (!continuationIndentStack->empty() 1340 && continuationIndentCount < continuationIndentStack->back()) 1341 continuationIndentCount = continuationIndentStack->back(); 1342 1343 // the block opener is not indented for a NonInStatementArray 1344 if ((isNonInStatementArray && i >= 0 && line[i] == '{') 1345 && !isInEnum && !braceBlockStateStack->empty() && braceBlockStateStack->back()) 1346 continuationIndentCount = 0; 1347 1348 continuationIndentStack->emplace_back(continuationIndentCount); 1349 } 1350 1351 /** 1352 * Register a continuation indent for a class header or a class initializer colon. 1353 */ 1354 void ASBeautifier::registerContinuationIndentColon(const string& line, int i, int tabIncrementIn) 1355 { 1356 assert(line[i] == ':'); 1357 assert(isInClassInitializer || isInClassHeaderTab); 1358 1359 // register indent at first word after the colon 1360 size_t firstChar = line.find_first_not_of(" \t"); 1361 if (firstChar == (size_t) i) // firstChar is ':' 1362 { 1363 size_t firstWord = line.find_first_not_of(" \t", firstChar + 1); 1364 if (firstWord != string::npos) 1365 { 1366 int continuationIndentCount = firstWord + spaceIndentCount + tabIncrementIn; 1367 continuationIndentStack->emplace_back(continuationIndentCount); 1368 isContinuation = true; 1369 } 1370 } 1371 } 1372 1373 /** 1374 * Compute indentation for a preprocessor #if statement. 1375 * This may be called for the activeBeautiferStack 1376 * instead of the active ASBeautifier object. 1377 */ 1378 pair<int, int> ASBeautifier::computePreprocessorIndent() 1379 { 1380 computePreliminaryIndentation(); 1381 pair<int, int> entry(indentCount, spaceIndentCount); 1382 if (!headerStack->empty() 1383 && entry.first > 0 1384 && (headerStack->back() == &AS_IF 1385 || headerStack->back() == &AS_ELSE 1386 || headerStack->back() == &AS_FOR 1387 || headerStack->back() == &AS_WHILE)) 1388 --entry.first; 1389 return entry; 1390 } 1391 1392 /** 1393 * get distance to the next non-white space, non-comment character in the line. 1394 * if no such character exists, return the length remaining to the end of the line. 1395 */ 1396 int ASBeautifier::getNextProgramCharDistance(const string& line, int i) const 1397 { 1398 bool inComment = false; 1399 int remainingCharNum = line.length() - i; 1400 int charDistance; 1401 char ch; 1402 1403 for (charDistance = 1; charDistance < remainingCharNum; charDistance++) 1404 { 1405 ch = line[i + charDistance]; 1406 if (inComment) 1407 { 1408 if (line.compare(i + charDistance, 2, "*/") == 0) 1409 { 1410 charDistance++; 1411 inComment = false; 1412 } 1413 continue; 1414 } 1415 else if (isWhiteSpace(ch)) 1416 continue; 1417 else if (ch == '/') 1418 { 1419 if (line.compare(i + charDistance, 2, "//") == 0) 1420 return remainingCharNum; 1421 if (line.compare(i + charDistance, 2, "/*") == 0) 1422 { 1423 charDistance++; 1424 inComment = true; 1425 } 1426 } 1427 else 1428 return charDistance; 1429 } 1430 1431 return charDistance; 1432 } 1433 1434 /** 1435 * find the index number of a string element in a container of strings 1436 * 1437 * @return the index number of element in the container. -1 if element not found. 1438 * @param container a vector of strings. 1439 * @param element the element to find . 1440 */ 1441 int ASBeautifier::indexOf(const vector<const string*>& container, const string* element) const 1442 { 1443 vector<const string*>::const_iterator where; 1444 1445 where = find(container.begin(), container.end(), element); 1446 if (where == container.end()) 1447 return -1; 1448 return (int) (where - container.begin()); 1449 } 1450 1451 /** 1452 * convert tabs to spaces. 1453 * i is the position of the character to convert to spaces. 1454 * tabIncrementIn is the increment that must be added for tab indent characters 1455 * to get the correct column for the current tab. 1456 */ 1457 int ASBeautifier::convertTabToSpaces(int i, int tabIncrementIn) const 1458 { 1459 int tabToSpacesAdjustment = indentLength - 1 - ((tabIncrementIn + i) % indentLength); 1460 return tabToSpacesAdjustment; 1461 } 1462 1463 /** 1464 * trim removes the white space surrounding a line. 1465 * 1466 * @return the trimmed line. 1467 * @param str the line to trim. 1468 */ 1469 string ASBeautifier::trim(const string& str) const 1470 { 1471 int start = 0; 1472 int end = str.length() - 1; 1473 1474 while (start < end && isWhiteSpace(str[start])) 1475 start++; 1476 1477 while (start <= end && isWhiteSpace(str[end])) 1478 end--; 1479 1480 // don't trim if it ends in a continuation 1481 if (end > -1 && str[end] == '\\') 1482 end = str.length() - 1; 1483 1484 string returnStr(str, start, end + 1 - start); 1485 return returnStr; 1486 } 1487 1488 /** 1489 * rtrim removes the white space from the end of a line. 1490 * 1491 * @return the trimmed line. 1492 * @param str the line to trim. 1493 */ 1494 string ASBeautifier::rtrim(const string& str) const 1495 { 1496 size_t len = str.length(); 1497 size_t end = str.find_last_not_of(" \t"); 1498 if (end == string::npos 1499 || end == len - 1) 1500 return str; 1501 string returnStr(str, 0, end + 1); 1502 return returnStr; 1503 } 1504 1505 /** 1506 * Copy tempStacks for the copy constructor. 1507 * The value of the vectors must also be copied. 1508 */ 1509 vector<vector<const string*>*>* ASBeautifier::copyTempStacks(const ASBeautifier& other) const 1510 { 1511 vector<vector<const string*>*>* tempStacksNew = new vector<vector<const string*>*>; 1512 vector<vector<const string*>*>::iterator iter; 1513 for (iter = other.tempStacks->begin(); 1514 iter != other.tempStacks->end(); 1515 ++iter) 1516 { 1517 vector<const string*>* newVec = new vector<const string*>; 1518 *newVec = **iter; 1519 tempStacksNew->emplace_back(newVec); 1520 } 1521 return tempStacksNew; 1522 } 1523 1524 /** 1525 * delete a member vectors to eliminate memory leak reporting 1526 */ 1527 void ASBeautifier::deleteBeautifierVectors() 1528 { 1529 beautifierFileType = 9; // reset to an invalid type 1530 delete headers; 1531 delete nonParenHeaders; 1532 delete preBlockStatements; 1533 delete preCommandHeaders; 1534 delete assignmentOperators; 1535 delete nonAssignmentOperators; 1536 delete indentableHeaders; 1537 } 1538 1539 /** 1540 * delete a vector object 1541 * T is the type of vector 1542 * used for all vectors except tempStacks 1543 */ 1544 template<typename T> 1545 void ASBeautifier::deleteContainer(T& container) 1546 { 1547 if (container != nullptr) 1548 { 1549 container->clear(); 1550 delete (container); 1551 container = nullptr; 1552 } 1553 } 1554 1555 /** 1556 * Delete the ASBeautifier vector object. 1557 * This is a vector of pointers to ASBeautifier objects allocated with the 'new' operator. 1558 * Therefore the ASBeautifier objects have to be deleted in addition to the 1559 * ASBeautifier pointer entries. 1560 */ 1561 void ASBeautifier::deleteBeautifierContainer(vector<ASBeautifier*>*& container) 1562 { 1563 if (container != nullptr) 1564 { 1565 vector<ASBeautifier*>::iterator iter = container->begin(); 1566 while (iter < container->end()) 1567 { 1568 delete *iter; 1569 ++iter; 1570 } 1571 container->clear(); 1572 delete (container); 1573 container = nullptr; 1574 } 1575 } 1576 1577 /** 1578 * Delete the tempStacks vector object. 1579 * The tempStacks is a vector of pointers to strings allocated with the 'new' operator. 1580 * Therefore the strings have to be deleted in addition to the tempStacks entries. 1581 */ 1582 void ASBeautifier::deleteTempStacksContainer(vector<vector<const string*>*>*& container) 1583 { 1584 if (container != nullptr) 1585 { 1586 vector<vector<const string*>*>::iterator iter = container->begin(); 1587 while (iter < container->end()) 1588 { 1589 delete *iter; 1590 ++iter; 1591 } 1592 container->clear(); 1593 delete (container); 1594 container = nullptr; 1595 } 1596 } 1597 1598 /** 1599 * initialize a vector object 1600 * T is the type of vector used for all vectors 1601 */ 1602 template<typename T> 1603 void ASBeautifier::initContainer(T& container, T value) 1604 { 1605 // since the ASFormatter object is never deleted, 1606 // the existing vectors must be deleted before creating new ones 1607 if (container != nullptr) 1608 deleteContainer(container); 1609 container = value; 1610 } 1611 1612 /** 1613 * Initialize the tempStacks vector object. 1614 * The tempStacks is a vector of pointers to strings allocated with the 'new' operator. 1615 * Any residual entries are deleted before the vector is initialized. 1616 */ 1617 void ASBeautifier::initTempStacksContainer(vector<vector<const string*>*>*& container, 1618 vector<vector<const string*>*>* value) 1619 { 1620 if (container != nullptr) 1621 deleteTempStacksContainer(container); 1622 container = value; 1623 } 1624 1625 /** 1626 * Determine if an assignment statement ends with a comma 1627 * that is not in a function argument. It ends with a 1628 * comma if a comma is the last char on the line. 1629 * 1630 * @return true if line ends with a comma, otherwise false. 1631 */ 1632 bool ASBeautifier::statementEndsWithComma(const string& line, int index) const 1633 { 1634 assert(line[index] == '='); 1635 1636 bool isInComment_ = false; 1637 bool isInQuote_ = false; 1638 int parenCount = 0; 1639 size_t lineLength = line.length(); 1640 size_t i = 0; 1641 char quoteChar_ = ' '; 1642 1643 for (i = index + 1; i < lineLength; ++i) 1644 { 1645 char ch = line[i]; 1646 1647 if (isInComment_) 1648 { 1649 if (line.compare(i, 2, "*/") == 0) 1650 { 1651 isInComment_ = false; 1652 ++i; 1653 } 1654 continue; 1655 } 1656 1657 if (ch == '\\') 1658 { 1659 ++i; 1660 continue; 1661 } 1662 1663 if (isInQuote_) 1664 { 1665 if (ch == quoteChar_) 1666 isInQuote_ = false; 1667 continue; 1668 } 1669 1670 if (ch == '"' 1671 || (ch == '\'' && !isDigitSeparator(line, i))) 1672 { 1673 isInQuote_ = true; 1674 quoteChar_ = ch; 1675 continue; 1676 } 1677 1678 if (line.compare(i, 2, "//") == 0) 1679 break; 1680 1681 if (line.compare(i, 2, "/*") == 0) 1682 { 1683 if (isLineEndComment(line, i)) 1684 break; 1685 else 1686 { 1687 isInComment_ = true; 1688 ++i; 1689 continue; 1690 } 1691 } 1692 1693 if (ch == '(') 1694 parenCount++; 1695 if (ch == ')') 1696 parenCount--; 1697 } 1698 if (isInComment_ 1699 || isInQuote_ 1700 || parenCount > 0) 1701 return false; 1702 1703 size_t lastChar = line.find_last_not_of(" \t", i - 1); 1704 1705 if (lastChar == string::npos || line[lastChar] != ',') 1706 return false; 1707 1708 return true; 1709 } 1710 1711 /** 1712 * check if current comment is a line-end comment 1713 * 1714 * @return is before a line-end comment. 1715 */ 1716 bool ASBeautifier::isLineEndComment(const string& line, int startPos) const 1717 { 1718 assert(line.compare(startPos, 2, "/*") == 0); 1719 1720 // comment must be closed on this line with nothing after it 1721 size_t endNum = line.find("*/", startPos + 2); 1722 if (endNum != string::npos) 1723 { 1724 size_t nextChar = line.find_first_not_of(" \t", endNum + 2); 1725 if (nextChar == string::npos) 1726 return true; 1727 } 1728 return false; 1729 } 1730 1731 /** 1732 * get the previous word index for an assignment operator 1733 * 1734 * @return is the index to the previous word (the in statement indent). 1735 */ 1736 int ASBeautifier::getContinuationIndentAssign(const string& line, size_t currPos) const 1737 { 1738 assert(line[currPos] == '='); 1739 1740 if (currPos == 0) 1741 return 0; 1742 1743 // get the last legal word (may be a number) 1744 size_t end = line.find_last_not_of(" \t", currPos - 1); 1745 if (end == string::npos || !isLegalNameChar(line[end])) 1746 return 0; 1747 1748 int start; // start of the previous word 1749 for (start = end; start > -1; start--) 1750 { 1751 if (!isLegalNameChar(line[start])) 1752 break; 1753 } 1754 start++; 1755 1756 return start; 1757 } 1758 1759 /** 1760 * get the instatement indent for a comma 1761 * 1762 * @return is the indent to the second word on the line (the in statement indent). 1763 */ 1764 int ASBeautifier::getContinuationIndentComma(const string& line, size_t currPos) const 1765 { 1766 assert(line[currPos] == ','); 1767 1768 // get first word on a line 1769 size_t indent = line.find_first_not_of(" \t"); 1770 if (indent == string::npos || !isLegalNameChar(line[indent])) 1771 return 0; 1772 1773 // bypass first word 1774 for (; indent < currPos; indent++) 1775 { 1776 if (!isLegalNameChar(line[indent])) 1777 break; 1778 } 1779 indent++; 1780 if (indent >= currPos || indent < 4) 1781 return 0; 1782 1783 // point to second word or assignment operator 1784 indent = line.find_first_not_of(" \t", indent); 1785 if (indent == string::npos || indent >= currPos) 1786 return 0; 1787 1788 return indent; 1789 } 1790 1791 /** 1792 * get the next word on a line 1793 * the argument 'currPos' must point to the current position. 1794 * 1795 * @return is the next word or an empty string if none found. 1796 */ 1797 string ASBeautifier::getNextWord(const string& line, size_t currPos) const 1798 { 1799 size_t lineLength = line.length(); 1800 // get the last legal word (may be a number) 1801 if (currPos == lineLength - 1) 1802 return string(); 1803 1804 size_t start = line.find_first_not_of(" \t", currPos + 1); 1805 if (start == string::npos || !isLegalNameChar(line[start])) 1806 return string(); 1807 1808 size_t end; // end of the current word 1809 for (end = start + 1; end <= lineLength; end++) 1810 { 1811 if (!isLegalNameChar(line[end]) || line[end] == '.') 1812 break; 1813 } 1814 1815 return line.substr(start, end - start); 1816 } 1817 1818 /** 1819 * Check if a preprocessor directive is always indented. 1820 * C# "region" and "endregion" are always indented. 1821 * C/C++ "pragma omp" is always indented. 1822 * 1823 * @return is true or false. 1824 */ 1825 bool ASBeautifier::isIndentedPreprocessor(const string& line, size_t currPos) const 1826 { 1827 assert(line[0] == '#'); 1828 string nextWord = getNextWord(line, currPos); 1829 if (nextWord == "region" || nextWord == "endregion") 1830 return true; 1831 // is it #pragma omp 1832 if (nextWord == "pragma") 1833 { 1834 // find pragma 1835 size_t start = line.find("pragma"); 1836 if (start == string::npos || !isLegalNameChar(line[start])) 1837 return false; 1838 // bypass pragma 1839 for (; start < line.length(); start++) 1840 { 1841 if (!isLegalNameChar(line[start])) 1842 break; 1843 } 1844 start++; 1845 if (start >= line.length()) 1846 return false; 1847 // point to start of second word 1848 start = line.find_first_not_of(" \t", start); 1849 if (start == string::npos) 1850 return false; 1851 // point to end of second word 1852 size_t end; 1853 for (end = start; end < line.length(); end++) 1854 { 1855 if (!isLegalNameChar(line[end])) 1856 break; 1857 } 1858 // check for "pragma omp" 1859 string word = line.substr(start, end - start); 1860 if (word == "omp" || word == "region" || word == "endregion") 1861 return true; 1862 } 1863 return false; 1864 } 1865 1866 /** 1867 * Check if a preprocessor directive is checking for __cplusplus defined. 1868 * 1869 * @return is true or false. 1870 */ 1871 bool ASBeautifier::isPreprocessorConditionalCplusplus(const string& line) const 1872 { 1873 string preproc = trim(line.substr(1)); 1874 if (preproc.compare(0, 5, "ifdef") == 0 && getNextWord(preproc, 4) == "__cplusplus") 1875 return true; 1876 if (preproc.compare(0, 2, "if") == 0) 1877 { 1878 // check for " #if defined(__cplusplus)" 1879 size_t charNum = 2; 1880 charNum = preproc.find_first_not_of(" \t", charNum); 1881 if (charNum != string::npos && preproc.compare(charNum, 7, "defined") == 0) 1882 { 1883 charNum += 7; 1884 charNum = preproc.find_first_not_of(" \t", charNum); 1885 if (charNum != string::npos && preproc.compare(charNum, 1, "(") == 0) 1886 { 1887 ++charNum; 1888 charNum = preproc.find_first_not_of(" \t", charNum); 1889 if (charNum != string::npos && preproc.compare(charNum, 11, "__cplusplus") == 0) 1890 return true; 1891 } 1892 } 1893 } 1894 return false; 1895 } 1896 1897 /** 1898 * Check if a preprocessor definition contains an unterminated comment. 1899 * Comments within a preprocessor definition can be continued without the backslash. 1900 * 1901 * @return is true or false. 1902 */ 1903 bool ASBeautifier::isInPreprocessorUnterminatedComment(const string& line) 1904 { 1905 if (!isInPreprocessorComment) 1906 { 1907 size_t startPos = line.find("/*"); 1908 if (startPos == string::npos) 1909 return false; 1910 } 1911 size_t endNum = line.find("*/"); 1912 if (endNum != string::npos) 1913 { 1914 isInPreprocessorComment = false; 1915 return false; 1916 } 1917 isInPreprocessorComment = true; 1918 return true; 1919 } 1920 1921 void ASBeautifier::popLastContinuationIndent() 1922 { 1923 assert(!continuationIndentStackSizeStack->empty()); 1924 int previousIndentStackSize = continuationIndentStackSizeStack->back(); 1925 if (continuationIndentStackSizeStack->size() > 1) 1926 continuationIndentStackSizeStack->pop_back(); 1927 while (previousIndentStackSize < (int) continuationIndentStack->size()) 1928 continuationIndentStack->pop_back(); 1929 } 1930 1931 // for unit testing 1932 int ASBeautifier::getBeautifierFileType() const 1933 { return beautifierFileType; } 1934 1935 /** 1936 * Process preprocessor statements and update the beautifier stacks. 1937 */ 1938 void ASBeautifier::processPreprocessor(const string& preproc, const string& line) 1939 { 1940 // When finding a multi-lined #define statement, the original beautifier 1941 // 1. sets its isInDefineDefinition flag 1942 // 2. clones a new beautifier that will be used for the actual indentation 1943 // of the #define. This clone is put into the activeBeautifierStack in order 1944 // to be called for the actual indentation. 1945 // The original beautifier will have isInDefineDefinition = true, isInDefine = false 1946 // The cloned beautifier will have isInDefineDefinition = true, isInDefine = true 1947 if (shouldIndentPreprocDefine && preproc == "define" && line[line.length() - 1] == '\\') 1948 { 1949 if (!isInDefineDefinition) 1950 { 1951 // this is the original beautifier 1952 isInDefineDefinition = true; 1953 1954 // push a new beautifier into the active stack 1955 // this beautifier will be used for the indentation of this define 1956 ASBeautifier* defineBeautifier = new ASBeautifier(*this); 1957 activeBeautifierStack->emplace_back(defineBeautifier); 1958 } 1959 else 1960 { 1961 // the is the cloned beautifier that is in charge of indenting the #define. 1962 isInDefine = true; 1963 } 1964 } 1965 else if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") 1966 { 1967 if (isPreprocessorConditionalCplusplus(line) && !g_preprocessorCppExternCBrace) 1968 g_preprocessorCppExternCBrace = 1; 1969 // push a new beautifier into the stack 1970 waitingBeautifierStackLengthStack->push_back(waitingBeautifierStack->size()); 1971 activeBeautifierStackLengthStack->push_back(activeBeautifierStack->size()); 1972 if (activeBeautifierStackLengthStack->back() == 0) 1973 waitingBeautifierStack->emplace_back(new ASBeautifier(*this)); 1974 else 1975 waitingBeautifierStack->emplace_back(new ASBeautifier(*activeBeautifierStack->back())); 1976 } 1977 else if (preproc == "else") 1978 { 1979 if ((waitingBeautifierStack != nullptr) && !waitingBeautifierStack->empty()) 1980 { 1981 // MOVE current waiting beautifier to active stack. 1982 activeBeautifierStack->emplace_back(waitingBeautifierStack->back()); 1983 waitingBeautifierStack->pop_back(); 1984 } 1985 } 1986 else if (preproc == "elif") 1987 { 1988 if ((waitingBeautifierStack != nullptr) && !waitingBeautifierStack->empty()) 1989 { 1990 // append a COPY current waiting beautifier to active stack, WITHOUT deleting the original. 1991 activeBeautifierStack->emplace_back(new ASBeautifier(*(waitingBeautifierStack->back()))); 1992 } 1993 } 1994 else if (preproc == "endif") 1995 { 1996 int stackLength = 0; 1997 ASBeautifier* beautifier = nullptr; 1998 1999 if (waitingBeautifierStackLengthStack != nullptr && !waitingBeautifierStackLengthStack->empty()) 2000 { 2001 stackLength = waitingBeautifierStackLengthStack->back(); 2002 waitingBeautifierStackLengthStack->pop_back(); 2003 while ((int) waitingBeautifierStack->size() > stackLength) 2004 { 2005 beautifier = waitingBeautifierStack->back(); 2006 waitingBeautifierStack->pop_back(); 2007 delete beautifier; 2008 } 2009 } 2010 2011 if (!activeBeautifierStackLengthStack->empty()) 2012 { 2013 stackLength = activeBeautifierStackLengthStack->back(); 2014 activeBeautifierStackLengthStack->pop_back(); 2015 while ((int) activeBeautifierStack->size() > stackLength) 2016 { 2017 beautifier = activeBeautifierStack->back(); 2018 activeBeautifierStack->pop_back(); 2019 delete beautifier; 2020 } 2021 } 2022 } 2023 } 2024 2025 // Compute the preliminary indentation based on data in the headerStack 2026 // and data from previous lines. 2027 // Update the class variable indentCount. 2028 void ASBeautifier::computePreliminaryIndentation() 2029 { 2030 indentCount = 0; 2031 spaceIndentCount = 0; 2032 isInClassHeaderTab = false; 2033 2034 if (isInObjCMethodDefinition && !continuationIndentStack->empty()) 2035 spaceIndentObjCMethodAlignment = continuationIndentStack->back(); 2036 2037 if (!continuationIndentStack->empty()) 2038 spaceIndentCount = continuationIndentStack->back(); 2039 2040 for (size_t i = 0; i < headerStack->size(); i++) 2041 { 2042 isInClass = false; 2043 2044 if (blockIndent) 2045 { 2046 // do NOT indent opening block for these headers 2047 if (!((*headerStack)[i] == &AS_NAMESPACE 2048 || (*headerStack)[i] == &AS_MODULE 2049 || (*headerStack)[i] == &AS_CLASS 2050 || (*headerStack)[i] == &AS_STRUCT 2051 || (*headerStack)[i] == &AS_UNION 2052 || (*headerStack)[i] == &AS_INTERFACE 2053 || (*headerStack)[i] == &AS_THROWS 2054 || (*headerStack)[i] == &AS_STATIC)) 2055 ++indentCount; 2056 } 2057 else if (!(i > 0 && (*headerStack)[i - 1] != &AS_OPEN_BRACE 2058 && (*headerStack)[i] == &AS_OPEN_BRACE)) 2059 ++indentCount; 2060 2061 if (!isJavaStyle() && !namespaceIndent && i > 0 2062 && ((*headerStack)[i - 1] == &AS_NAMESPACE 2063 || (*headerStack)[i - 1] == &AS_MODULE) 2064 && (*headerStack)[i] == &AS_OPEN_BRACE) 2065 --indentCount; 2066 2067 if (isCStyle() && i >= 1 2068 && (*headerStack)[i - 1] == &AS_CLASS 2069 && (*headerStack)[i] == &AS_OPEN_BRACE) 2070 { 2071 if (classIndent) 2072 ++indentCount; 2073 isInClass = true; 2074 } 2075 2076 // is the switchIndent option is on, indent switch statements an additional indent. 2077 else if (switchIndent && i > 1 2078 && (*headerStack)[i - 1] == &AS_SWITCH 2079 && (*headerStack)[i] == &AS_OPEN_BRACE) 2080 { 2081 ++indentCount; 2082 isInSwitch = true; 2083 } 2084 2085 } // end of for loop 2086 2087 if (isInClassHeader) 2088 { 2089 if (!isJavaStyle()) 2090 isInClassHeaderTab = true; 2091 if (lineOpensWithLineComment || lineStartsInComment || lineOpensWithComment) 2092 { 2093 if (!lineBeginsWithOpenBrace) 2094 --indentCount; 2095 if (!continuationIndentStack->empty()) 2096 spaceIndentCount -= continuationIndentStack->back(); 2097 } 2098 else if (blockIndent) 2099 { 2100 if (!lineBeginsWithOpenBrace) 2101 ++indentCount; 2102 } 2103 } 2104 2105 if (isInClassInitializer || isInEnumTypeID) 2106 { 2107 indentCount += classInitializerIndents; 2108 } 2109 2110 if (isInEnum && lineBeginsWithComma && !continuationIndentStack->empty()) 2111 { 2112 // unregister '=' indent from the previous line 2113 continuationIndentStack->pop_back(); 2114 isContinuation = false; 2115 spaceIndentCount = 0; 2116 } 2117 2118 // Objective-C interface continuation line 2119 if (isInObjCInterface) 2120 ++indentCount; 2121 2122 // unindent a class closing brace... 2123 if (!lineStartsInComment 2124 && isCStyle() 2125 && isInClass 2126 && classIndent 2127 && headerStack->size() >= 2 2128 && (*headerStack)[headerStack->size() - 2] == &AS_CLASS 2129 && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE 2130 && lineBeginsWithCloseBrace 2131 && braceBlockStateStack->back()) 2132 --indentCount; 2133 2134 // unindent an indented switch closing brace... 2135 else if (!lineStartsInComment 2136 && isInSwitch 2137 && switchIndent 2138 && headerStack->size() >= 2 2139 && (*headerStack)[headerStack->size() - 2] == &AS_SWITCH 2140 && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE 2141 && lineBeginsWithCloseBrace) 2142 --indentCount; 2143 2144 // handle special case of run-in comment in an indented class statement 2145 if (isInClass 2146 && classIndent 2147 && isInRunInComment 2148 && !lineOpensWithComment 2149 && headerStack->size() > 1 2150 && (*headerStack)[headerStack->size() - 2] == &AS_CLASS) 2151 --indentCount; 2152 2153 if (isInConditional) 2154 --indentCount; 2155 if (g_preprocessorCppExternCBrace >= 4) 2156 --indentCount; 2157 } 2158 2159 void ASBeautifier::adjustParsedLineIndentation(size_t iPrelim, bool isInExtraHeaderIndent) 2160 { 2161 if (lineStartsInComment) 2162 return; 2163 2164 // unindent a one-line statement in a header indent 2165 if (!blockIndent 2166 && lineBeginsWithOpenBrace 2167 && headerStack->size() < iPrelim 2168 && isInExtraHeaderIndent 2169 && (lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum) 2170 && shouldIndentBracedLine) 2171 --indentCount; 2172 2173 /* 2174 * if '{' doesn't follow an immediately previous '{' in the headerStack 2175 * (but rather another header such as "for" or "if", then unindent it 2176 * by one indentation relative to its block. 2177 */ 2178 else if (!blockIndent 2179 && lineBeginsWithOpenBrace 2180 && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum) 2181 && (headerStack->size() > 1 && (*headerStack)[headerStack->size() - 2] != &AS_OPEN_BRACE) 2182 && shouldIndentBracedLine) 2183 --indentCount; 2184 2185 // must check one less in headerStack if more than one header on a line (allow-addins)... 2186 else if (headerStack->size() > iPrelim + 1 2187 && !blockIndent 2188 && lineBeginsWithOpenBrace 2189 && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum) 2190 && (headerStack->size() > 2 && (*headerStack)[headerStack->size() - 3] != &AS_OPEN_BRACE) 2191 && shouldIndentBracedLine) 2192 --indentCount; 2193 2194 // unindent a closing brace... 2195 else if (lineBeginsWithCloseBrace 2196 && shouldIndentBracedLine) 2197 --indentCount; 2198 2199 // correctly indent one-line-blocks... 2200 else if (lineOpeningBlocksNum > 0 2201 && lineOpeningBlocksNum == lineClosingBlocksNum 2202 && previousLineProbationTab) 2203 --indentCount; 2204 2205 if (indentCount < 0) 2206 indentCount = 0; 2207 2208 // take care of extra brace indentation option... 2209 if (!lineStartsInComment 2210 && braceIndent 2211 && shouldIndentBracedLine 2212 && (lineBeginsWithOpenBrace || lineBeginsWithCloseBrace)) 2213 { 2214 if (!braceIndentVtk) 2215 ++indentCount; 2216 else 2217 { 2218 // determine if a style VTK brace is indented 2219 bool haveUnindentedBrace = false; 2220 for (size_t i = 0; i < headerStack->size(); i++) 2221 { 2222 if (((*headerStack)[i] == &AS_NAMESPACE 2223 || (*headerStack)[i] == &AS_MODULE 2224 || (*headerStack)[i] == &AS_CLASS 2225 || (*headerStack)[i] == &AS_STRUCT) 2226 && i + 1 < headerStack->size() 2227 && (*headerStack)[i + 1] == &AS_OPEN_BRACE) 2228 i++; 2229 else if (lineBeginsWithOpenBrace) 2230 { 2231 // don't double count the current brace 2232 if (i + 1 < headerStack->size() 2233 && (*headerStack)[i] == &AS_OPEN_BRACE) 2234 haveUnindentedBrace = true; 2235 } 2236 else if ((*headerStack)[i] == &AS_OPEN_BRACE) 2237 haveUnindentedBrace = true; 2238 } // end of for loop 2239 if (haveUnindentedBrace) 2240 ++indentCount; 2241 } 2242 } 2243 } 2244 2245 /** 2246 * Compute indentCount adjustment when in a series of else-if statements 2247 * and shouldBreakElseIfs is requested. 2248 * It increments by one for each 'else' in the tempStack. 2249 */ 2250 int ASBeautifier::adjustIndentCountForBreakElseIfComments() const 2251 { 2252 assert(isElseHeaderIndent && !tempStacks->empty()); 2253 int indentCountIncrement = 0; 2254 vector<const string*>* lastTempStack = tempStacks->back(); 2255 if (lastTempStack != nullptr) 2256 { 2257 for (size_t i = 0; i < lastTempStack->size(); i++) 2258 { 2259 if (*lastTempStack->at(i) == AS_ELSE) 2260 indentCountIncrement++; 2261 } 2262 } 2263 return indentCountIncrement; 2264 } 2265 2266 /** 2267 * Extract a preprocessor statement without the #. 2268 * If a error occurs an empty string is returned. 2269 */ 2270 string ASBeautifier::extractPreprocessorStatement(const string& line) const 2271 { 2272 string preproc; 2273 size_t start = line.find_first_not_of("#/ \t"); 2274 if (start == string::npos) 2275 return preproc; 2276 size_t end = line.find_first_of("/ \t", start); 2277 if (end == string::npos) 2278 end = line.length(); 2279 preproc = line.substr(start, end - start); 2280 return preproc; 2281 } 2282 2283 void ASBeautifier::adjustObjCMethodDefinitionIndentation(const string& line_) 2284 { 2285 // register indent for Objective-C continuation line 2286 if (line_.length() > 0 2287 && (line_[0] == '-' || line_[0] == '+')) 2288 { 2289 if (shouldAlignMethodColon && objCColonAlignSubsequent != -1) 2290 { 2291 string convertedLine = getIndentedSpaceEquivalent(line_); 2292 colonIndentObjCMethodAlignment = findObjCColonAlignment(convertedLine); 2293 int objCColonAlignSubsequentIndent = objCColonAlignSubsequent + indentLength; 2294 if (objCColonAlignSubsequentIndent > colonIndentObjCMethodAlignment) 2295 colonIndentObjCMethodAlignment = objCColonAlignSubsequentIndent; 2296 } 2297 else if (continuationIndentStack->empty() 2298 || continuationIndentStack->back() == 0) 2299 { 2300 continuationIndentStack->emplace_back(indentLength); 2301 isContinuation = true; 2302 } 2303 } 2304 // set indent for last definition line 2305 else if (!lineBeginsWithOpenBrace) 2306 { 2307 if (shouldAlignMethodColon) 2308 spaceIndentCount = computeObjCColonAlignment(line_, colonIndentObjCMethodAlignment); 2309 else if (continuationIndentStack->empty()) 2310 spaceIndentCount = spaceIndentObjCMethodAlignment; 2311 } 2312 } 2313 2314 void ASBeautifier::adjustObjCMethodCallIndentation(const string& line_) 2315 { 2316 static int keywordIndentObjCMethodAlignment = 0; 2317 if (shouldAlignMethodColon && objCColonAlignSubsequent != -1) 2318 { 2319 if (isInObjCMethodCallFirst) 2320 { 2321 isInObjCMethodCallFirst = false; 2322 string convertedLine = getIndentedSpaceEquivalent(line_); 2323 bracePosObjCMethodAlignment = convertedLine.find('['); 2324 keywordIndentObjCMethodAlignment = 2325 getObjCFollowingKeyword(convertedLine, bracePosObjCMethodAlignment); 2326 colonIndentObjCMethodAlignment = findObjCColonAlignment(convertedLine); 2327 if (colonIndentObjCMethodAlignment >= 0) 2328 { 2329 int objCColonAlignSubsequentIndent = objCColonAlignSubsequent + indentLength; 2330 if (objCColonAlignSubsequentIndent > colonIndentObjCMethodAlignment) 2331 colonIndentObjCMethodAlignment = objCColonAlignSubsequentIndent; 2332 if (lineBeginsWithOpenBrace) 2333 colonIndentObjCMethodAlignment -= indentLength; 2334 } 2335 } 2336 else 2337 { 2338 if (findObjCColonAlignment(line_) != -1) 2339 { 2340 if (colonIndentObjCMethodAlignment < 0) 2341 spaceIndentCount += computeObjCColonAlignment(line_, objCColonAlignSubsequent); 2342 else if (objCColonAlignSubsequent > colonIndentObjCMethodAlignment) 2343 spaceIndentCount = computeObjCColonAlignment(line_, objCColonAlignSubsequent); 2344 else 2345 spaceIndentCount = computeObjCColonAlignment(line_, colonIndentObjCMethodAlignment); 2346 } 2347 else 2348 { 2349 if (spaceIndentCount < colonIndentObjCMethodAlignment) 2350 spaceIndentCount += keywordIndentObjCMethodAlignment; 2351 } 2352 } 2353 } 2354 else // align keywords instead of colons 2355 { 2356 if (isInObjCMethodCallFirst) 2357 { 2358 isInObjCMethodCallFirst = false; 2359 string convertedLine = getIndentedSpaceEquivalent(line_); 2360 bracePosObjCMethodAlignment = convertedLine.find('['); 2361 keywordIndentObjCMethodAlignment = 2362 getObjCFollowingKeyword(convertedLine, bracePosObjCMethodAlignment); 2363 } 2364 else 2365 { 2366 if (spaceIndentCount < keywordIndentObjCMethodAlignment + bracePosObjCMethodAlignment) 2367 spaceIndentCount += keywordIndentObjCMethodAlignment; 2368 } 2369 } 2370 } 2371 2372 /** 2373 * Clear the variables used to align the Objective-C method definitions. 2374 */ 2375 void ASBeautifier::clearObjCMethodDefinitionAlignment() 2376 { 2377 assert(isImmediatelyPostObjCMethodDefinition); 2378 spaceIndentCount = 0; 2379 spaceIndentObjCMethodAlignment = 0; 2380 colonIndentObjCMethodAlignment = 0; 2381 isInObjCMethodDefinition = false; 2382 isImmediatelyPostObjCMethodDefinition = false; 2383 if (!continuationIndentStack->empty()) 2384 continuationIndentStack->pop_back(); 2385 } 2386 2387 /** 2388 * Find the first alignment colon on a line. 2389 * Ternary operators (?) are bypassed. 2390 */ 2391 int ASBeautifier::findObjCColonAlignment(const string& line) const 2392 { 2393 bool haveTernary = false; 2394 for (size_t i = 0; i < line.length(); i++) 2395 { 2396 i = line.find_first_of(":?", i); 2397 if (i == string::npos) 2398 break; 2399 2400 if (line[i] == '?') 2401 { 2402 haveTernary = true; 2403 continue; 2404 } 2405 if (haveTernary) 2406 { 2407 haveTernary = false; 2408 continue; 2409 } 2410 return i; 2411 } 2412 return -1; 2413 } 2414 2415 /** 2416 * Compute the spaceIndentCount necessary to align the current line colon 2417 * with the colon position in the argument. 2418 * If it cannot be aligned indentLength is returned and a new colon 2419 * position is calculated. 2420 */ 2421 int ASBeautifier::computeObjCColonAlignment(const string& line, int colonAlignPosition) const 2422 { 2423 int colonPosition = findObjCColonAlignment(line); 2424 if (colonPosition < 0 || colonPosition > colonAlignPosition) 2425 return indentLength; 2426 return (colonAlignPosition - colonPosition); 2427 } 2428 2429 /* 2430 * Compute position of the keyword following the method call object. 2431 * This is oversimplified to find unusual method calls. 2432 * Use for now and see what happens. 2433 * Most programmers will probably use align-method-colon anyway. 2434 */ 2435 int ASBeautifier::getObjCFollowingKeyword(const string& line, int bracePos) const 2436 { 2437 assert(line[bracePos] == '['); 2438 size_t firstText = line.find_first_not_of(" \t", bracePos + 1); 2439 if (firstText == string::npos) 2440 return -(indentCount * indentLength - 1); 2441 size_t searchBeg = firstText; 2442 size_t objectEnd = 0; // end of object text 2443 if (line[searchBeg] == '[') 2444 { 2445 objectEnd = line.find(']', searchBeg + 1); 2446 if (objectEnd == string::npos) 2447 return 0; 2448 } 2449 else 2450 { 2451 if (line[searchBeg] == '(') 2452 { 2453 searchBeg = line.find(')', searchBeg + 1); 2454 if (searchBeg == string::npos) 2455 return 0; 2456 } 2457 // bypass the object name 2458 objectEnd = line.find_first_of(" \t", searchBeg + 1); 2459 if (objectEnd == string::npos) 2460 return 0; 2461 --objectEnd; 2462 } 2463 size_t keyPos = line.find_first_not_of(" \t", objectEnd + 1); 2464 if (keyPos == string::npos) 2465 return 0; 2466 return keyPos - firstText; 2467 } 2468 2469 /** 2470 * Get a line using the current space indent with all tabs replaced by spaces. 2471 * The indentCount is NOT included 2472 * Needed to compute an accurate alignment. 2473 */ 2474 string ASBeautifier::getIndentedSpaceEquivalent(const string& line_) const 2475 { 2476 string spaceIndent; 2477 spaceIndent.append(spaceIndentCount, ' '); 2478 string convertedLine = spaceIndent + line_; 2479 for (size_t i = spaceIndent.length(); i < convertedLine.length(); i++) 2480 { 2481 if (convertedLine[i] == '\t') 2482 { 2483 size_t numSpaces = indentLength - (i % indentLength); 2484 convertedLine.replace(i, 1, numSpaces, ' '); 2485 i += indentLength - 1; 2486 } 2487 } 2488 return convertedLine; 2489 } 2490 2491 /** 2492 * Determine if an item is at a top level. 2493 */ 2494 bool ASBeautifier::isTopLevel() const 2495 { 2496 if (headerStack->empty()) 2497 return true; 2498 else if (headerStack->back() == &AS_OPEN_BRACE 2499 && headerStack->size() >= 2) 2500 { 2501 if ((*headerStack)[headerStack->size() - 2] == &AS_NAMESPACE 2502 || (*headerStack)[headerStack->size() - 2] == &AS_MODULE 2503 || (*headerStack)[headerStack->size() - 2] == &AS_CLASS 2504 || (*headerStack)[headerStack->size() - 2] == &AS_INTERFACE 2505 || (*headerStack)[headerStack->size() - 2] == &AS_STRUCT 2506 || (*headerStack)[headerStack->size() - 2] == &AS_UNION) 2507 return true; 2508 } 2509 else if (headerStack->back() == &AS_NAMESPACE 2510 || headerStack->back() == &AS_MODULE 2511 || headerStack->back() == &AS_CLASS 2512 || headerStack->back() == &AS_INTERFACE 2513 || headerStack->back() == &AS_STRUCT 2514 || headerStack->back() == &AS_UNION) 2515 return true; 2516 return false; 2517 } 2518 2519 /** 2520 * Parse the current line to update indentCount and spaceIndentCount. 2521 */ 2522 void ASBeautifier::parseCurrentLine(const string& line) 2523 { 2524 bool isInLineComment = false; 2525 bool isInOperator = false; 2526 bool isSpecialChar = false; 2527 bool haveCaseIndent = false; 2528 bool haveAssignmentThisLine = false; 2529 bool closingBraceReached = false; 2530 bool previousLineProbation = (probationHeader != nullptr); 2531 char ch = ' '; 2532 int tabIncrementIn = 0; 2533 if (isInQuote 2534 && !haveLineContinuationChar 2535 && !isInVerbatimQuote 2536 && !isInAsm) 2537 isInQuote = false; // missing closing quote 2538 haveLineContinuationChar = false; 2539 2540 for (size_t i = 0; i < line.length(); i++) 2541 { 2542 ch = line[i]; 2543 2544 if (isInBeautifySQL) 2545 continue; 2546 2547 // handle special characters (i.e. backslash+character such as \n, \t, ...) 2548 if (isInQuote && !isInVerbatimQuote) 2549 { 2550 if (isSpecialChar) 2551 { 2552 isSpecialChar = false; 2553 continue; 2554 } 2555 if (line.compare(i, 2, "\\\\") == 0) 2556 { 2557 i++; 2558 continue; 2559 } 2560 if (ch == '\\') 2561 { 2562 if (peekNextChar(line, i) == ' ') // is this '\' at end of line 2563 haveLineContinuationChar = true; 2564 else 2565 isSpecialChar = true; 2566 continue; 2567 } 2568 } 2569 else if (isInDefine && ch == '\\') 2570 continue; 2571 2572 // bypass whitespace here 2573 if (isWhiteSpace(ch)) 2574 { 2575 if (ch == '\t') 2576 tabIncrementIn += convertTabToSpaces(i, tabIncrementIn); 2577 continue; 2578 } 2579 2580 // handle quotes (such as 'x' and "Hello Dolly") 2581 if (!(isInComment || isInLineComment) 2582 && (ch == '"' 2583 || (ch == '\'' && !isDigitSeparator(line, i)))) 2584 { 2585 if (!isInQuote) 2586 { 2587 quoteChar = ch; 2588 isInQuote = true; 2589 char prevCh = i > 0 ? line[i - 1] : ' '; 2590 if (isCStyle() && prevCh == 'R') 2591 { 2592 int parenPos = line.find('(', i); 2593 if (parenPos != -1) 2594 { 2595 isInVerbatimQuote = true; 2596 verbatimDelimiter = line.substr(i + 1, parenPos - i - 1); 2597 } 2598 } 2599 else if (isSharpStyle() && prevCh == '@') 2600 isInVerbatimQuote = true; 2601 // check for "C" following "extern" 2602 else if (g_preprocessorCppExternCBrace == 2 && line.compare(i, 3, "\"C\"") == 0) 2603 ++g_preprocessorCppExternCBrace; 2604 } 2605 else if (isInVerbatimQuote && ch == '"') 2606 { 2607 if (isCStyle()) 2608 { 2609 string delim = ')' + verbatimDelimiter; 2610 int delimStart = i - delim.length(); 2611 if (delimStart > 0 && line.substr(delimStart, delim.length()) == delim) 2612 { 2613 isInQuote = false; 2614 isInVerbatimQuote = false; 2615 } 2616 } 2617 else if (isSharpStyle()) 2618 { 2619 if (line.compare(i, 2, "\"\"") == 0) 2620 i++; 2621 else 2622 { 2623 isInQuote = false; 2624 isInVerbatimQuote = false; 2625 continue; 2626 } 2627 } 2628 } 2629 else if (quoteChar == ch) 2630 { 2631 isInQuote = false; 2632 isContinuation = true; 2633 continue; 2634 } 2635 } 2636 if (isInQuote) 2637 continue; 2638 2639 // handle comments 2640 2641 if (!(isInComment || isInLineComment) && line.compare(i, 2, "//") == 0) 2642 { 2643 // if there is a 'case' statement after these comments unindent by 1 2644 if (isCaseHeaderCommentIndent) 2645 --indentCount; 2646 // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested 2647 // if there is an 'else' after these comments a tempStacks indent is required 2648 if (isElseHeaderIndent && lineOpensWithLineComment && !tempStacks->empty()) 2649 indentCount += adjustIndentCountForBreakElseIfComments(); 2650 isInLineComment = true; 2651 i++; 2652 continue; 2653 } 2654 else if (!(isInComment || isInLineComment) && line.compare(i, 2, "/*") == 0) 2655 { 2656 // if there is a 'case' statement after these comments unindent by 1 2657 if (isCaseHeaderCommentIndent && lineOpensWithComment) 2658 --indentCount; 2659 // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested 2660 // if there is an 'else' after these comments a tempStacks indent is required 2661 if (isElseHeaderIndent && lineOpensWithComment && !tempStacks->empty()) 2662 indentCount += adjustIndentCountForBreakElseIfComments(); 2663 isInComment = true; 2664 i++; 2665 if (!lineOpensWithComment) // does line start with comment? 2666 blockCommentNoIndent = true; // if no, cannot indent continuation lines 2667 continue; 2668 } 2669 else if ((isInComment || isInLineComment) && line.compare(i, 2, "*/") == 0) 2670 { 2671 size_t firstText = line.find_first_not_of(" \t"); 2672 // if there is a 'case' statement after these comments unindent by 1 2673 // only if the ending comment is the first entry on the line 2674 if (isCaseHeaderCommentIndent && firstText == i) 2675 --indentCount; 2676 // if this comment close starts the line, must check for else-if indent 2677 // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested 2678 // if there is an 'else' after these comments a tempStacks indent is required 2679 if (firstText == i) 2680 { 2681 if (isElseHeaderIndent && !lineOpensWithComment && !tempStacks->empty()) 2682 indentCount += adjustIndentCountForBreakElseIfComments(); 2683 } 2684 isInComment = false; 2685 i++; 2686 blockCommentNoIndent = false; // ok to indent next comment 2687 continue; 2688 } 2689 // treat indented preprocessor lines as a line comment 2690 else if (line[0] == '#' && isIndentedPreprocessor(line, i)) 2691 { 2692 isInLineComment = true; 2693 } 2694 2695 if (isInLineComment) 2696 { 2697 // bypass rest of the comment up to the comment end 2698 while (i + 1 < line.length()) 2699 i++; 2700 2701 continue; 2702 } 2703 if (isInComment) 2704 { 2705 // if there is a 'case' statement after these comments unindent by 1 2706 if (!lineOpensWithComment && isCaseHeaderCommentIndent) 2707 --indentCount; 2708 // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested 2709 // if there is an 'else' after these comments a tempStacks indent is required 2710 if (!lineOpensWithComment && isElseHeaderIndent && !tempStacks->empty()) 2711 indentCount += adjustIndentCountForBreakElseIfComments(); 2712 // bypass rest of the comment up to the comment end 2713 while (i + 1 < line.length() 2714 && line.compare(i + 1, 2, "*/") != 0) 2715 i++; 2716 2717 continue; 2718 } 2719 2720 // if we have reached this far then we are NOT in a comment or string of special character... 2721 2722 if (probationHeader != nullptr) 2723 { 2724 if ((probationHeader == &AS_STATIC && ch == '{') 2725 || (probationHeader == &AS_SYNCHRONIZED && ch == '(')) 2726 { 2727 // insert the probation header as a new header 2728 isInHeader = true; 2729 headerStack->emplace_back(probationHeader); 2730 2731 // handle the specific probation header 2732 isInConditional = (probationHeader == &AS_SYNCHRONIZED); 2733 2734 isContinuation = false; 2735 // if the probation comes from the previous line, then indent by 1 tab count. 2736 if (previousLineProbation 2737 && ch == '{' 2738 && !(blockIndent && probationHeader == &AS_STATIC)) 2739 { 2740 ++indentCount; 2741 previousLineProbationTab = true; 2742 } 2743 previousLineProbation = false; 2744 } 2745 2746 // dismiss the probation header 2747 probationHeader = nullptr; 2748 } 2749 2750 prevNonSpaceCh = currentNonSpaceCh; 2751 currentNonSpaceCh = ch; 2752 if (!isLegalNameChar(ch) && ch != ',' && ch != ';') 2753 { 2754 prevNonLegalCh = currentNonLegalCh; 2755 currentNonLegalCh = ch; 2756 } 2757 2758 if (isInHeader) 2759 { 2760 isInHeader = false; 2761 currentHeader = headerStack->back(); 2762 } 2763 else 2764 currentHeader = nullptr; 2765 2766 if (isCStyle() && isInTemplate 2767 && (ch == '<' || ch == '>') 2768 && !(line.length() > i + 1 && line.compare(i, 2, ">=") == 0)) 2769 { 2770 if (ch == '<') 2771 { 2772 ++templateDepth; 2773 continuationIndentStackSizeStack->push_back(continuationIndentStack->size()); 2774 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true); 2775 } 2776 else if (ch == '>') 2777 { 2778 popLastContinuationIndent(); 2779 if (--templateDepth <= 0) 2780 { 2781 ch = ';'; 2782 isInTemplate = false; 2783 templateDepth = 0; 2784 } 2785 } 2786 } 2787 2788 // handle parentheses 2789 if (ch == '(' || ch == '[' || ch == ')' || ch == ']') 2790 { 2791 if (ch == '(' || ch == '[') 2792 { 2793 isInOperator = false; 2794 // if have a struct header, this is a declaration not a definition 2795 if (ch == '(' 2796 && !headerStack->empty() 2797 && headerStack->back() == &AS_STRUCT) 2798 { 2799 headerStack->pop_back(); 2800 isInClassHeader = false; 2801 if (line.find(AS_STRUCT, 0) > i) // if not on this line 2802 indentCount -= classInitializerIndents; 2803 if (indentCount < 0) 2804 indentCount = 0; 2805 } 2806 2807 if (parenDepth == 0) 2808 { 2809 parenStatementStack->push_back(isContinuation); 2810 isContinuation = true; 2811 } 2812 parenDepth++; 2813 if (ch == '[') 2814 { 2815 ++squareBracketCount; 2816 if (squareBracketCount == 1 && isCStyle()) 2817 { 2818 isInObjCMethodCall = true; 2819 isInObjCMethodCallFirst = true; 2820 } 2821 } 2822 2823 continuationIndentStackSizeStack->push_back(continuationIndentStack->size()); 2824 2825 if (currentHeader != nullptr) 2826 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, minConditionalIndent, true); 2827 else if (!isInObjCMethodDefinition) 2828 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true); 2829 } 2830 else if (ch == ')' || ch == ']') 2831 { 2832 if (ch == ']') 2833 --squareBracketCount; 2834 if (squareBracketCount <= 0) 2835 { 2836 squareBracketCount = 0; 2837 if (isInObjCMethodCall) 2838 isImmediatelyPostObjCMethodCall = true; 2839 } 2840 foundPreCommandHeader = false; 2841 parenDepth--; 2842 if (parenDepth == 0) 2843 { 2844 if (!parenStatementStack->empty()) // in case of unmatched closing parens 2845 { 2846 isContinuation = parenStatementStack->back(); 2847 parenStatementStack->pop_back(); 2848 } 2849 isInAsm = false; 2850 isInConditional = false; 2851 } 2852 2853 if (!continuationIndentStackSizeStack->empty()) 2854 { 2855 popLastContinuationIndent(); 2856 2857 if (!parenIndentStack->empty()) 2858 { 2859 int poppedIndent = parenIndentStack->back(); 2860 parenIndentStack->pop_back(); 2861 2862 if (i == 0) 2863 spaceIndentCount = poppedIndent; 2864 } 2865 } 2866 } 2867 continue; 2868 } 2869 2870 if (ch == '{') 2871 { 2872 // first, check if '{' is a block-opener or a static-array opener 2873 bool isBlockOpener = ((prevNonSpaceCh == '{' && braceBlockStateStack->back()) 2874 || prevNonSpaceCh == '}' 2875 || prevNonSpaceCh == ')' 2876 || prevNonSpaceCh == ';' 2877 || peekNextChar(line, i) == '{' 2878 || isInTrailingReturnType 2879 || foundPreCommandHeader 2880 || foundPreCommandMacro 2881 || isInClassHeader 2882 || (isInClassInitializer && !isLegalNameChar(prevNonSpaceCh)) 2883 || isNonInStatementArray 2884 || isInObjCMethodDefinition 2885 || isInObjCInterface 2886 || isSharpAccessor 2887 || isSharpDelegate 2888 || isInExternC 2889 || isInAsmBlock 2890 || getNextWord(line, i) == AS_NEW 2891 || (isInDefine 2892 && (prevNonSpaceCh == '(' 2893 || isLegalNameChar(prevNonSpaceCh)))); 2894 2895 if (isInObjCMethodDefinition) 2896 { 2897 objCColonAlignSubsequent = 0; 2898 isImmediatelyPostObjCMethodDefinition = true; 2899 if (lineBeginsWithOpenBrace) // for run-in braces 2900 clearObjCMethodDefinitionAlignment(); 2901 } 2902 2903 if (!isBlockOpener && !isContinuation && !isInClassInitializer && !isInEnum) 2904 { 2905 if (isTopLevel()) 2906 isBlockOpener = true; 2907 } 2908 2909 if (!isBlockOpener && currentHeader != nullptr) 2910 { 2911 for (size_t n = 0; n < nonParenHeaders->size(); n++) 2912 if (currentHeader == (*nonParenHeaders)[n]) 2913 { 2914 isBlockOpener = true; 2915 break; 2916 } 2917 } 2918 2919 braceBlockStateStack->push_back(isBlockOpener); 2920 2921 if (!isBlockOpener) 2922 { 2923 continuationIndentStackSizeStack->push_back(continuationIndentStack->size()); 2924 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true); 2925 parenDepth++; 2926 if (i == 0) 2927 shouldIndentBracedLine = false; 2928 isInEnumTypeID = false; 2929 2930 continue; 2931 } 2932 2933 // this brace is a block opener... 2934 2935 ++lineOpeningBlocksNum; 2936 2937 if (isInClassInitializer || isInEnumTypeID) 2938 { 2939 // decrease tab count if brace is broken 2940 if (lineBeginsWithOpenBrace) 2941 { 2942 indentCount -= classInitializerIndents; 2943 // decrease one more if an empty class 2944 if (!headerStack->empty() 2945 && (*headerStack).back() == &AS_CLASS) 2946 { 2947 int nextChar = getNextProgramCharDistance(line, i); 2948 if ((int) line.length() > nextChar && line[nextChar] == '}') 2949 --indentCount; 2950 } 2951 } 2952 } 2953 2954 if (isInObjCInterface) 2955 { 2956 isInObjCInterface = false; 2957 if (lineBeginsWithOpenBrace) 2958 --indentCount; 2959 } 2960 2961 if (braceIndent && !namespaceIndent && !headerStack->empty() 2962 && ((*headerStack).back() == &AS_NAMESPACE 2963 || (*headerStack).back() == &AS_MODULE)) 2964 { 2965 shouldIndentBracedLine = false; 2966 --indentCount; 2967 } 2968 2969 // an indentable struct is treated like a class in the header stack 2970 if (!headerStack->empty() 2971 && (*headerStack).back() == &AS_STRUCT 2972 && isInIndentableStruct) 2973 (*headerStack).back() = &AS_CLASS; 2974 2975 // is a brace inside a paren? 2976 parenDepthStack->emplace_back(parenDepth); 2977 blockStatementStack->push_back(isContinuation); 2978 2979 if (!continuationIndentStack->empty()) 2980 { 2981 // completely purge the continuationIndentStack 2982 while (!continuationIndentStack->empty()) 2983 popLastContinuationIndent(); 2984 if (isInClassInitializer || isInClassHeaderTab) 2985 { 2986 if (lineBeginsWithOpenBrace || lineBeginsWithComma) 2987 spaceIndentCount = 0; 2988 } 2989 else 2990 spaceIndentCount = 0; 2991 } 2992 2993 blockTabCount += (isContinuation ? 1 : 0); 2994 if (g_preprocessorCppExternCBrace == 3) 2995 ++g_preprocessorCppExternCBrace; 2996 parenDepth = 0; 2997 isInTrailingReturnType = false; 2998 isInClassHeader = false; 2999 isInClassHeaderTab = false; 3000 isInClassInitializer = false; 3001 isInEnumTypeID = false; 3002 isContinuation = false; 3003 isInQuestion = false; 3004 isInLet = false; 3005 foundPreCommandHeader = false; 3006 foundPreCommandMacro = false; 3007 isInExternC = false; 3008 3009 tempStacks->emplace_back(new vector<const string*>); 3010 headerStack->emplace_back(&AS_OPEN_BRACE); 3011 lastLineHeader = &AS_OPEN_BRACE; 3012 3013 continue; 3014 } // end '{' 3015 3016 //check if a header has been reached 3017 bool isPotentialHeader = isCharPotentialHeader(line, i); 3018 3019 if (isPotentialHeader && squareBracketCount == 0) 3020 { 3021 const string* newHeader = findHeader(line, i, headers); 3022 3023 // java can have a 'default' not in a switch 3024 if (newHeader == &AS_DEFAULT 3025 && peekNextChar(line, (i + (*newHeader).length() - 1)) != ':') 3026 newHeader = nullptr; 3027 // Qt headers may be variables in C++ 3028 if (isCStyle() 3029 && (newHeader == &AS_FOREVER || newHeader == &AS_FOREACH)) 3030 { 3031 if (line.find_first_of("=;", i) != string::npos) 3032 newHeader = nullptr; 3033 } 3034 else if (isSharpStyle() 3035 && (newHeader == &AS_GET || newHeader == &AS_SET)) 3036 { 3037 if (getNextWord(line, i + (*newHeader).length()) == "is") 3038 newHeader = nullptr; 3039 } 3040 else if (newHeader == &AS_USING 3041 && peekNextChar(line, i + (*newHeader).length() - 1) != '(') 3042 newHeader = nullptr; 3043 3044 if (newHeader != nullptr) 3045 { 3046 // if we reached here, then this is a header... 3047 bool isIndentableHeader = true; 3048 3049 isInHeader = true; 3050 3051 vector<const string*>* lastTempStack = nullptr;; 3052 if (!tempStacks->empty()) 3053 lastTempStack = tempStacks->back(); 3054 3055 // if a new block is opened, push a new stack into tempStacks to hold the 3056 // future list of headers in the new block. 3057 3058 // take care of the special case: 'else if (...)' 3059 if (newHeader == &AS_IF && lastLineHeader == &AS_ELSE) 3060 { 3061 if (!headerStack->empty()) 3062 headerStack->pop_back(); 3063 } 3064 3065 // take care of 'else' 3066 else if (newHeader == &AS_ELSE) 3067 { 3068 if (lastTempStack != nullptr) 3069 { 3070 int indexOfIf = indexOf(*lastTempStack, &AS_IF); 3071 if (indexOfIf != -1) 3072 { 3073 // recreate the header list in headerStack up to the previous 'if' 3074 // from the temporary snapshot stored in lastTempStack. 3075 int restackSize = lastTempStack->size() - indexOfIf - 1; 3076 for (int r = 0; r < restackSize; r++) 3077 { 3078 headerStack->emplace_back(lastTempStack->back()); 3079 lastTempStack->pop_back(); 3080 } 3081 if (!closingBraceReached) 3082 indentCount += restackSize; 3083 } 3084 /* 3085 * If the above if is not true, i.e. no 'if' before the 'else', 3086 * then nothing beautiful will come out of this... 3087 * I should think about inserting an Exception here to notify the caller of this... 3088 */ 3089 } 3090 } 3091 3092 // check if 'while' closes a previous 'do' 3093 else if (newHeader == &AS_WHILE) 3094 { 3095 if (lastTempStack != nullptr) 3096 { 3097 int indexOfDo = indexOf(*lastTempStack, &AS_DO); 3098 if (indexOfDo != -1) 3099 { 3100 // recreate the header list in headerStack up to the previous 'do' 3101 // from the temporary snapshot stored in lastTempStack. 3102 int restackSize = lastTempStack->size() - indexOfDo - 1; 3103 for (int r = 0; r < restackSize; r++) 3104 { 3105 headerStack->emplace_back(lastTempStack->back()); 3106 lastTempStack->pop_back(); 3107 } 3108 if (!closingBraceReached) 3109 indentCount += restackSize; 3110 } 3111 } 3112 } 3113 // check if 'catch' closes a previous 'try' or 'catch' 3114 else if (newHeader == &AS_CATCH || newHeader == &AS_FINALLY) 3115 { 3116 if (lastTempStack != nullptr) 3117 { 3118 int indexOfTry = indexOf(*lastTempStack, &AS_TRY); 3119 if (indexOfTry == -1) 3120 indexOfTry = indexOf(*lastTempStack, &AS_CATCH); 3121 if (indexOfTry != -1) 3122 { 3123 // recreate the header list in headerStack up to the previous 'try' 3124 // from the temporary snapshot stored in lastTempStack. 3125 int restackSize = lastTempStack->size() - indexOfTry - 1; 3126 for (int r = 0; r < restackSize; r++) 3127 { 3128 headerStack->emplace_back(lastTempStack->back()); 3129 lastTempStack->pop_back(); 3130 } 3131 3132 if (!closingBraceReached) 3133 indentCount += restackSize; 3134 } 3135 } 3136 } 3137 else if (newHeader == &AS_CASE) 3138 { 3139 isInCase = true; 3140 if (!haveCaseIndent) 3141 { 3142 haveCaseIndent = true; 3143 if (!lineBeginsWithOpenBrace) 3144 --indentCount; 3145 } 3146 } 3147 else if (newHeader == &AS_DEFAULT) 3148 { 3149 isInCase = true; 3150 --indentCount; 3151 } 3152 else if (newHeader == &AS_STATIC 3153 || newHeader == &AS_SYNCHRONIZED) 3154 { 3155 if (!headerStack->empty() 3156 && (headerStack->back() == &AS_STATIC 3157 || headerStack->back() == &AS_SYNCHRONIZED)) 3158 { 3159 isIndentableHeader = false; 3160 } 3161 else 3162 { 3163 isIndentableHeader = false; 3164 probationHeader = newHeader; 3165 } 3166 } 3167 else if (newHeader == &AS_TEMPLATE) 3168 { 3169 isInTemplate = true; 3170 isIndentableHeader = false; 3171 } 3172 3173 if (isIndentableHeader) 3174 { 3175 headerStack->emplace_back(newHeader); 3176 isContinuation = false; 3177 if (indexOf(*nonParenHeaders, newHeader) == -1) 3178 { 3179 isInConditional = true; 3180 } 3181 lastLineHeader = newHeader; 3182 } 3183 else 3184 isInHeader = false; 3185 3186 i += newHeader->length() - 1; 3187 3188 continue; 3189 } // newHeader != nullptr 3190 3191 if (findHeader(line, i, preCommandHeaders) != nullptr) 3192 // must be after function arguments 3193 if (prevNonSpaceCh == ')') 3194 foundPreCommandHeader = true; 3195 3196 // Objective-C NSException macros are preCommandHeaders 3197 if (isCStyle() && findKeyword(line, i, AS_NS_DURING)) 3198 foundPreCommandMacro = true; 3199 if (isCStyle() && findKeyword(line, i, AS_NS_HANDLER)) 3200 foundPreCommandMacro = true; 3201 3202 if (parenDepth == 0 && findKeyword(line, i, AS_ENUM)) 3203 isInEnum = true; 3204 3205 if (isSharpStyle() && findKeyword(line, i, AS_LET)) 3206 isInLet = true; 3207 3208 } // isPotentialHeader 3209 3210 if (ch == '?') 3211 isInQuestion = true; 3212 3213 // special handling of colons 3214 if (ch == ':') 3215 { 3216 if (line.length() > i + 1 && line[i + 1] == ':') // look for :: 3217 { 3218 ++i; 3219 continue; 3220 } 3221 else if (isInQuestion) 3222 { 3223 // do nothing special 3224 } 3225 else if (parenDepth > 0) 3226 { 3227 // found a 'for' loop or an objective-C statement 3228 // so do nothing special 3229 } 3230 else if (isInEnum) 3231 { 3232 // found an enum with a base-type 3233 isInEnumTypeID = true; 3234 if (i == 0) 3235 indentCount += classInitializerIndents; 3236 } 3237 else if ((isCStyle() || isSharpStyle()) 3238 && !isInCase 3239 && (prevNonSpaceCh == ')' || foundPreCommandHeader)) 3240 { 3241 // found a 'class' c'tor initializer 3242 isInClassInitializer = true; 3243 registerContinuationIndentColon(line, i, tabIncrementIn); 3244 if (i == 0) 3245 indentCount += classInitializerIndents; 3246 } 3247 else if (isInClassHeader || isInObjCInterface) 3248 { 3249 // is in a 'class A : public B' definition 3250 isInClassHeaderTab = true; 3251 registerContinuationIndentColon(line, i, tabIncrementIn); 3252 } 3253 else if (isInAsm || isInAsmOneLine || isInAsmBlock) 3254 { 3255 // do nothing special 3256 } 3257 else if (isDigit(peekNextChar(line, i))) 3258 { 3259 // found a bit field - do nothing special 3260 } 3261 else if (isCStyle() && isInClass && prevNonSpaceCh != ')') 3262 { 3263 // found a 'private:' or 'public:' inside a class definition 3264 --indentCount; 3265 if (modifierIndent) 3266 spaceIndentCount += (indentLength / 2); 3267 } 3268 else if (isCStyle() && !isInClass 3269 && headerStack->size() >= 2 3270 && (*headerStack)[headerStack->size() - 2] == &AS_CLASS 3271 && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE) 3272 { 3273 // found a 'private:' or 'public:' inside a class definition 3274 // and on the same line as the class opening brace 3275 // do nothing 3276 } 3277 else if (isJavaStyle() && lastLineHeader == &AS_FOR) 3278 { 3279 // found a java for-each statement 3280 // so do nothing special 3281 } 3282 else 3283 { 3284 currentNonSpaceCh = ';'; // so that braces after the ':' will appear as block-openers 3285 char peekedChar = peekNextChar(line, i); 3286 if (isInCase) 3287 { 3288 isInCase = false; 3289 ch = ';'; // from here on, treat char as ';' 3290 } 3291 else if (isCStyle() || (isSharpStyle() && peekedChar == ';')) 3292 { 3293 // is in a label (e.g. 'label1:') 3294 if (labelIndent) 3295 --indentCount; // unindent label by one indent 3296 else if (!lineBeginsWithOpenBrace) 3297 indentCount = 0; // completely flush indent to left 3298 } 3299 } 3300 } 3301 3302 if ((ch == ';' || (parenDepth > 0 && ch == ',')) && !continuationIndentStackSizeStack->empty()) 3303 while ((int) continuationIndentStackSizeStack->back() + (parenDepth > 0 ? 1 : 0) 3304 < (int) continuationIndentStack->size()) 3305 continuationIndentStack->pop_back(); 3306 3307 else if (ch == ',' && isInEnum && isNonInStatementArray && !continuationIndentStack->empty()) 3308 continuationIndentStack->pop_back(); 3309 3310 // handle commas 3311 // previous "isInStatement" will be from an assignment operator or class initializer 3312 if (ch == ',' && parenDepth == 0 && !isContinuation && !isNonInStatementArray) 3313 { 3314 // is comma at end of line 3315 size_t nextChar = line.find_first_not_of(" \t", i + 1); 3316 if (nextChar != string::npos) 3317 { 3318 if (line.compare(nextChar, 2, "//") == 0 3319 || line.compare(nextChar, 2, "/*") == 0) 3320 nextChar = string::npos; 3321 } 3322 // register indent 3323 if (nextChar == string::npos) 3324 { 3325 // register indent at previous word 3326 if (isJavaStyle() && isInClassHeader) 3327 { 3328 // do nothing for now 3329 } 3330 // register indent at second word on the line 3331 else if (!isInTemplate && !isInClassHeaderTab && !isInClassInitializer) 3332 { 3333 int prevWord = getContinuationIndentComma(line, i); 3334 int continuationIndentCount = prevWord + spaceIndentCount + tabIncrementIn; 3335 continuationIndentStack->emplace_back(continuationIndentCount); 3336 isContinuation = true; 3337 } 3338 } 3339 } 3340 // handle comma first initializers 3341 if (ch == ',' && parenDepth == 0 && lineBeginsWithComma 3342 && (isInClassInitializer || isInClassHeaderTab)) 3343 spaceIndentCount = 0; 3344 3345 // handle ends of statements 3346 if ((ch == ';' && parenDepth == 0) || ch == '}') 3347 { 3348 if (ch == '}') 3349 { 3350 // first check if this '}' closes a previous block, or a static array... 3351 if (braceBlockStateStack->size() > 1) 3352 { 3353 bool braceBlockState = braceBlockStateStack->back(); 3354 braceBlockStateStack->pop_back(); 3355 if (!braceBlockState) 3356 { 3357 if (!continuationIndentStackSizeStack->empty()) 3358 { 3359 // this brace is a static array 3360 popLastContinuationIndent(); 3361 parenDepth--; 3362 if (i == 0) 3363 shouldIndentBracedLine = false; 3364 3365 if (!parenIndentStack->empty()) 3366 { 3367 int poppedIndent = parenIndentStack->back(); 3368 parenIndentStack->pop_back(); 3369 if (i == 0) 3370 spaceIndentCount = poppedIndent; 3371 } 3372 } 3373 continue; 3374 } 3375 } 3376 3377 // this brace is block closer... 3378 3379 ++lineClosingBlocksNum; 3380 3381 if (!continuationIndentStackSizeStack->empty()) 3382 popLastContinuationIndent(); 3383 3384 if (!parenDepthStack->empty()) 3385 { 3386 parenDepth = parenDepthStack->back(); 3387 parenDepthStack->pop_back(); 3388 isContinuation = blockStatementStack->back(); 3389 blockStatementStack->pop_back(); 3390 3391 if (isContinuation) 3392 blockTabCount--; 3393 } 3394 3395 closingBraceReached = true; 3396 if (i == 0) 3397 spaceIndentCount = 0; 3398 isInAsmBlock = false; 3399 isInAsm = isInAsmOneLine = isInQuote = false; // close these just in case 3400 3401 int headerPlace = indexOf(*headerStack, &AS_OPEN_BRACE); 3402 if (headerPlace != -1) 3403 { 3404 const string* popped = headerStack->back(); 3405 while (popped != &AS_OPEN_BRACE) 3406 { 3407 headerStack->pop_back(); 3408 popped = headerStack->back(); 3409 } 3410 headerStack->pop_back(); 3411 3412 if (headerStack->empty()) 3413 g_preprocessorCppExternCBrace = 0; 3414 3415 // do not indent namespace brace unless namespaces are indented 3416 if (!namespaceIndent && !headerStack->empty() 3417 && ((*headerStack).back() == &AS_NAMESPACE 3418 || (*headerStack).back() == &AS_MODULE) 3419 && i == 0) // must be the first brace on the line 3420 shouldIndentBracedLine = false; 3421 3422 if (!tempStacks->empty()) 3423 { 3424 vector<const string*>* temp = tempStacks->back(); 3425 tempStacks->pop_back(); 3426 delete temp; 3427 } 3428 } 3429 3430 ch = ' '; // needed due to cases such as '}else{', so that headers ('else' in this case) will be identified... 3431 } // ch == '}' 3432 3433 /* 3434 * Create a temporary snapshot of the current block's header-list in the 3435 * uppermost inner stack in tempStacks, and clear the headerStack up to 3436 * the beginning of the block. 3437 * Thus, the next future statement will think it comes one indent past 3438 * the block's '{' unless it specifically checks for a companion-header 3439 * (such as a previous 'if' for an 'else' header) within the tempStacks, 3440 * and recreates the temporary snapshot by manipulating the tempStacks. 3441 */ 3442 if (!tempStacks->back()->empty()) 3443 while (!tempStacks->back()->empty()) 3444 tempStacks->back()->pop_back(); 3445 while (!headerStack->empty() && headerStack->back() != &AS_OPEN_BRACE) 3446 { 3447 tempStacks->back()->emplace_back(headerStack->back()); 3448 headerStack->pop_back(); 3449 } 3450 3451 if (parenDepth == 0 && ch == ';') 3452 { 3453 isContinuation = false; 3454 isInClassInitializer = false; 3455 } 3456 3457 if (isInObjCMethodDefinition) 3458 { 3459 objCColonAlignSubsequent = 0; 3460 isImmediatelyPostObjCMethodDefinition = true; 3461 } 3462 3463 previousLastLineHeader = nullptr; 3464 isInClassHeader = false; // for 'friend' class 3465 isInEnum = false; 3466 isInEnumTypeID = false; 3467 isInQuestion = false; 3468 isInTemplate = false; 3469 isInObjCInterface = false; 3470 foundPreCommandHeader = false; 3471 foundPreCommandMacro = false; 3472 squareBracketCount = 0; 3473 3474 continue; 3475 } 3476 3477 if (isPotentialHeader) 3478 { 3479 // check for preBlockStatements in C/C++ ONLY if not within parentheses 3480 // (otherwise 'struct XXX' statements would be wrongly interpreted...) 3481 if (!isInTemplate && !(isCStyle() && parenDepth > 0)) 3482 { 3483 const string* newHeader = findHeader(line, i, preBlockStatements); 3484 // CORBA IDL module 3485 if (newHeader == &AS_MODULE) 3486 { 3487 char nextChar = peekNextChar(line, i + newHeader->length() - 1); 3488 if (prevNonSpaceCh == ')' || !isalpha(nextChar)) 3489 newHeader = nullptr; 3490 } 3491 if (newHeader != nullptr 3492 && !(isCStyle() && newHeader == &AS_CLASS && isInEnum) // is not 'enum class' 3493 && !(isCStyle() && newHeader == &AS_INTERFACE // CORBA IDL interface 3494 && (headerStack->empty() 3495 || headerStack->back() != &AS_OPEN_BRACE))) 3496 { 3497 if (!isSharpStyle()) 3498 headerStack->emplace_back(newHeader); 3499 // do not need 'where' in the headerStack 3500 // do not need second 'class' statement in a row 3501 else if (!(newHeader == &AS_WHERE 3502 || ((newHeader == &AS_CLASS || newHeader == &AS_STRUCT) 3503 && !headerStack->empty() 3504 && (headerStack->back() == &AS_CLASS 3505 || headerStack->back() == &AS_STRUCT)))) 3506 headerStack->emplace_back(newHeader); 3507 3508 if (!headerStack->empty()) 3509 { 3510 if ((*headerStack).back() == &AS_CLASS 3511 || (*headerStack).back() == &AS_STRUCT 3512 || (*headerStack).back() == &AS_INTERFACE) 3513 { 3514 isInClassHeader = true; 3515 } 3516 else if ((*headerStack).back() == &AS_NAMESPACE 3517 || (*headerStack).back() == &AS_MODULE) 3518 { 3519 // remove continuationIndent from namespace 3520 if (!continuationIndentStack->empty()) 3521 continuationIndentStack->pop_back(); 3522 isContinuation = false; 3523 } 3524 } 3525 3526 i += newHeader->length() - 1; 3527 continue; 3528 } 3529 } 3530 const string* foundIndentableHeader = findHeader(line, i, indentableHeaders); 3531 3532 if (foundIndentableHeader != nullptr) 3533 { 3534 // must bypass the header before registering the in statement 3535 i += foundIndentableHeader->length() - 1; 3536 if (!isInOperator && !isInTemplate && !isNonInStatementArray) 3537 { 3538 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, false); 3539 isContinuation = true; 3540 } 3541 continue; 3542 } 3543 3544 if (isCStyle() && findKeyword(line, i, AS_OPERATOR)) 3545 isInOperator = true; 3546 3547 if (g_preprocessorCppExternCBrace == 1 && findKeyword(line, i, AS_EXTERN)) 3548 ++g_preprocessorCppExternCBrace; 3549 3550 if (g_preprocessorCppExternCBrace == 3) // extern "C" is not followed by a '{' 3551 g_preprocessorCppExternCBrace = 0; 3552 3553 // "new" operator is a pointer, not a calculation 3554 if (findKeyword(line, i, AS_NEW)) 3555 { 3556 if (isContinuation && !continuationIndentStack->empty() && prevNonSpaceCh == '=') 3557 continuationIndentStack->back() = 0; 3558 } 3559 3560 if (isCStyle() && findKeyword(line, i, AS_AUTO) && isTopLevel()) 3561 { 3562 isInTrailingReturnType = true; 3563 } 3564 3565 if (isCStyle()) 3566 { 3567 if (findKeyword(line, i, AS_ASM) 3568 || findKeyword(line, i, AS__ASM__)) 3569 { 3570 isInAsm = true; 3571 } 3572 else if (findKeyword(line, i, AS_MS_ASM) // microsoft specific 3573 || findKeyword(line, i, AS_MS__ASM)) 3574 { 3575 int index = 4; 3576 if (peekNextChar(line, i) == '_') // check for __asm 3577 index = 5; 3578 3579 char peekedChar = peekNextChar(line, i + index); 3580 if (peekedChar == '{' || peekedChar == ' ') 3581 isInAsmBlock = true; 3582 else 3583 isInAsmOneLine = true; 3584 } 3585 } 3586 3587 // bypass the entire name for all others 3588 string name = getCurrentWord(line, i); 3589 i += name.length() - 1; 3590 continue; 3591 } 3592 3593 // Handle Objective-C statements 3594 3595 if (ch == '@' 3596 && line.length() > i + 1 3597 && !isWhiteSpace(line[i + 1]) 3598 && isCharPotentialHeader(line, i + 1)) 3599 { 3600 string curWord = getCurrentWord(line, i + 1); 3601 if (curWord == AS_INTERFACE) 3602 { 3603 isInObjCInterface = true; 3604 string name = '@' + curWord; 3605 i += name.length() - 1; 3606 continue; 3607 } 3608 else if (isInObjCInterface) 3609 { 3610 --indentCount; 3611 isInObjCInterface = false; 3612 } 3613 3614 if (curWord == AS_PUBLIC 3615 || curWord == AS_PRIVATE 3616 || curWord == AS_PROTECTED) 3617 { 3618 --indentCount; 3619 if (modifierIndent) 3620 spaceIndentCount += (indentLength / 2); 3621 string name = '@' + curWord; 3622 i += name.length() - 1; 3623 continue; 3624 } 3625 else if (curWord == AS_END) 3626 { 3627 popLastContinuationIndent(); 3628 spaceIndentCount = 0; 3629 isInObjCMethodDefinition = false; 3630 string name = '@' + curWord; 3631 i += name.length() - 1; 3632 continue; 3633 } 3634 } 3635 else if ((ch == '-' || ch == '+') 3636 && (prevNonSpaceCh == ';' || prevNonSpaceCh == '{' 3637 || headerStack->empty() || isInObjCInterface) 3638 && ASBase::peekNextChar(line, i) != '-' 3639 && ASBase::peekNextChar(line, i) != '+' 3640 && line.find_first_not_of(" \t") == i) 3641 { 3642 if (isInObjCInterface) 3643 --indentCount; 3644 isInObjCInterface = false; 3645 isInObjCMethodDefinition = true; 3646 continue; 3647 } 3648 3649 // Handle operators 3650 3651 bool isPotentialOperator = isCharPotentialOperator(ch); 3652 3653 if (isPotentialOperator) 3654 { 3655 // Check if an operator has been reached. 3656 const string* foundAssignmentOp = findOperator(line, i, assignmentOperators); 3657 const string* foundNonAssignmentOp = findOperator(line, i, nonAssignmentOperators); 3658 3659 if (foundNonAssignmentOp != nullptr) 3660 { 3661 if (foundNonAssignmentOp == &AS_LAMBDA) 3662 foundPreCommandHeader = true; 3663 if (isInTemplate && foundNonAssignmentOp == &AS_GR_GR) 3664 foundNonAssignmentOp = nullptr; 3665 } 3666 3667 // Since findHeader's boundary checking was not used above, it is possible 3668 // that both an assignment op and a non-assignment op where found, 3669 // e.g. '>>' and '>>='. If this is the case, treat the LONGER one as the 3670 // found operator. 3671 if (foundAssignmentOp != nullptr && foundNonAssignmentOp != nullptr) 3672 { 3673 if (foundAssignmentOp->length() < foundNonAssignmentOp->length()) 3674 foundAssignmentOp = nullptr; 3675 else 3676 foundNonAssignmentOp = nullptr; 3677 } 3678 3679 if (foundNonAssignmentOp != nullptr) 3680 { 3681 if (foundNonAssignmentOp->length() > 1) 3682 i += foundNonAssignmentOp->length() - 1; 3683 3684 // For C++ input/output, operator<< and >> should be 3685 // aligned, if we are not in a statement already and 3686 // also not in the "operator<<(...)" header line 3687 if (!isInOperator 3688 && continuationIndentStack->empty() 3689 && isCStyle() 3690 && (foundNonAssignmentOp == &AS_GR_GR 3691 || foundNonAssignmentOp == &AS_LS_LS)) 3692 { 3693 // this will be true if the line begins with the operator 3694 if (i < foundNonAssignmentOp->length() && spaceIndentCount == 0) 3695 spaceIndentCount += 2 * indentLength; 3696 // align to the beginning column of the operator 3697 registerContinuationIndent(line, i - foundNonAssignmentOp->length(), spaceIndentCount, tabIncrementIn, 0, false); 3698 } 3699 } 3700 3701 else if (foundAssignmentOp != nullptr) 3702 { 3703 foundPreCommandHeader = false; // clears this for array assignments 3704 foundPreCommandMacro = false; 3705 3706 if (foundAssignmentOp->length() > 1) 3707 i += foundAssignmentOp->length() - 1; 3708 3709 if (!isInOperator && !isInTemplate && (!isNonInStatementArray || isInEnum)) 3710 { 3711 // if multiple assignments, align on the previous word 3712 if (foundAssignmentOp == &AS_ASSIGN 3713 && prevNonSpaceCh != ']' // an array 3714 && statementEndsWithComma(line, i)) 3715 { 3716 if (!haveAssignmentThisLine) // only one assignment indent per line 3717 { 3718 // register indent at previous word 3719 haveAssignmentThisLine = true; 3720 int prevWordIndex = getContinuationIndentAssign(line, i); 3721 int continuationIndentCount = prevWordIndex + spaceIndentCount + tabIncrementIn; 3722 continuationIndentStack->emplace_back(continuationIndentCount); 3723 isContinuation = true; 3724 } 3725 } 3726 // don't indent an assignment if 'let' 3727 else if (isInLet) 3728 { 3729 isInLet = false; 3730 } 3731 else if (!lineBeginsWithComma) 3732 { 3733 if (i == 0 && spaceIndentCount == 0) 3734 spaceIndentCount += indentLength; 3735 registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, false); 3736 isContinuation = true; 3737 } 3738 } 3739 } 3740 } 3741 } // end of for loop * end of for loop * end of for loop * end of for loop * end of for loop * 3742 } 3743 3744 } // end namespace astyle