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