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