PageRenderTime 116ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/src/align.cpp

http://github.com/bengardner/uncrustify
C++ | 2216 lines | 1632 code | 272 blank | 312 comment | 511 complexity | 7a287665be65b90b5c0021ea8d173cb1 MD5 | raw file
Possible License(s): GPL-2.0
  1. /**
  2. * @file align.cpp
  3. * Does all the aligning stuff.
  4. *
  5. * @author Ben Gardner
  6. * @author Guy Maurel since version 0.62 for uncrustify4Qt
  7. * October 2015, 2016
  8. * @license GPL v2+
  9. */
  10. #include "align.h"
  11. #include "uncrustify_types.h"
  12. #include "chunk_list.h"
  13. #include "ChunkStack.h"
  14. #include "align_stack.h"
  15. #include "prototypes.h"
  16. #include <cstdio>
  17. #include <cstdlib>
  18. #include <cstring>
  19. #include "unc_ctype.h"
  20. #include "uncrustify.h"
  21. #include "indent.h"
  22. #include "space.h"
  23. /*
  24. * Here are the items aligned:
  25. *
  26. * - enum value assignments
  27. * enum {
  28. * cat = 1,
  29. * fred = 2,
  30. * };
  31. *
  32. * - struct/union variable & bit definitions
  33. * struct foo {
  34. * char cat;
  35. * int id : 5;
  36. * int name_len : 6;
  37. * int height : 12;
  38. * };
  39. *
  40. * - variable definitions & assignments in normal code
  41. * const char *cat = "feline";
  42. * int id = 4;
  43. * a = 5;
  44. * bat = 14;
  45. *
  46. * - simple array initializers
  47. * int a[] = {
  48. * 1, 2, 3, 4, 5,
  49. * 6, 7, 8, 9, 10
  50. * };
  51. *
  52. * - c99 array initializers
  53. * const char *name[] = {
  54. * [FRED] = "fred",
  55. * [JOE] = "joe",
  56. * [PETER] = "peter",
  57. * };
  58. * struct foo b[] = {
  59. * { .id = 1, .name = "text 1" },
  60. * { .id = 567, .name = "text 2" },
  61. * };
  62. * struct foo_t bars[] =
  63. * {
  64. * [0] = { .name = "bar",
  65. * .age = 21 },
  66. * [1] = { .name = "barley",
  67. * .age = 55 },
  68. * };
  69. *
  70. * - compact array initializers
  71. * struct foo b[] = {
  72. * { 3, "dog" }, { 6, "spider" },
  73. * { 8, "elephant" }, { 3, "cat" },
  74. * };
  75. *
  76. * - multiline array initializers (2nd line indented, not aligned)
  77. * struct foo b[] = {
  78. * { AD_NOT_ALLOWED, "Sorry, you failed to guess the password.",
  79. * "Try again?", "Yes", "No" },
  80. * { AD_SW_ERROR, "A software error has occured.", "Bye!", NULL, NULL },
  81. * };
  82. *
  83. * - Trailing comments
  84. *
  85. * - Back-slash newline groups
  86. *
  87. * - Function prototypes
  88. * int foo();
  89. * void bar();
  90. *
  91. * - Preprocessors
  92. * #define FOO_VAL 15
  93. * #define MAX_TIMEOUT 60
  94. * #define FOO(x) ((x) * 65)
  95. *
  96. * - typedefs
  97. * typedef uint8_t BYTE;
  98. * typedef int32_t INT32;
  99. * typedef uint32_t UINT32;
  100. */
  101. /**
  102. * Aligns everything in the chunk stack to a particular column.
  103. * The stack is empty after this function.
  104. *
  105. * @param col the column
  106. * @param align_single align even if there is only one item on the stack
  107. */
  108. static void align_stack(ChunkStack &cs, size_t col, bool align_single, log_sev_t sev);
  109. /**
  110. * Scan everything at the current level until the close brace and find the
  111. * variable def align column. Also aligns bit-colons, but that assumes that
  112. * bit-types are the same! But that should always be the case...
  113. */
  114. static chunk_t *align_var_def_brace(chunk_t *pc, size_t span, size_t *nl_count);
  115. /**
  116. * For a series of lines ending in a comment, align them.
  117. * The series ends when more than align_right_cmt_span newlines are found.
  118. *
  119. * Interesting info:
  120. * - least physically allowed column
  121. * - intended column
  122. * - least original cmt column
  123. *
  124. * min_col is the minimum allowed column (based on prev token col/size)
  125. * cmt_col less than
  126. *
  127. * @param start Start point
  128. * @return pointer the last item looked at
  129. */
  130. static chunk_t *align_trailing_comments(chunk_t *start);
  131. /**
  132. * Generically aligns on '=', '{', '(' and item after ','
  133. * It scans the first line and picks up the location of those tags.
  134. * It then scans subsequent lines and adjusts the column.
  135. * Finally it does a second pass to align everything.
  136. *
  137. * Aligns all the '=' signs in structure assignments.
  138. * a = {
  139. * .a = 1;
  140. * .type = fast;
  141. * };
  142. *
  143. * And aligns on '{', numbers, strings, words.
  144. * colors[] = {
  145. * {"red", {255, 0, 0}}, {"blue", { 0, 255, 0}},
  146. * {"green", { 0, 0, 255}}, {"purple", {255, 255, 0}},
  147. * };
  148. *
  149. * For the C99 indexed array assignment, the leading []= is skipped (no aligning)
  150. * struct foo_t bars[] =
  151. * {
  152. * [0] = { .name = "bar",
  153. * .age = 21 },
  154. * [1] = { .name = "barley",
  155. * .age = 55 },
  156. * };
  157. *
  158. * NOTE: this assumes that spacing is at the minimum correct spacing (ie force)
  159. * if it isn't, some extra spaces will be inserted.
  160. *
  161. * @param start Points to the open brace chunk
  162. */
  163. static void align_init_brace(chunk_t *start);
  164. static void align_func_params(void);
  165. static void align_same_func_call_params(void);
  166. /**
  167. * Aligns all function prototypes in the file.
  168. */
  169. static void align_func_proto(size_t span);
  170. /**
  171. * Aligns all function prototypes in the file.
  172. */
  173. static void align_oc_msg_spec(size_t span);
  174. /**
  175. * Aligns simple typedefs that are contained on a single line each.
  176. * This should be called after the typedef target is marked as a type.
  177. *
  178. * typedef int foo_t;
  179. * typedef char bar_t;
  180. * typedef const char cc_t;
  181. */
  182. static void align_typedefs(size_t span);
  183. /**
  184. * Align '<<' (CT_ARITH?)
  185. */
  186. static void align_left_shift(void);
  187. /**
  188. * Aligns OC messages
  189. */
  190. static void align_oc_msg_colons(void);
  191. /**
  192. * Aligns an OC message
  193. *
  194. * @param so the square open of the message
  195. */
  196. static void align_oc_msg_colon(chunk_t *so);
  197. /**
  198. * Aligns OC declarations on the colon
  199. * -(void) doSomething: (NSString*) param1
  200. * with: (NSString*) param2
  201. */
  202. static void align_oc_decl_colon(void);
  203. /**
  204. * Aligns asm declarations on the colon
  205. * asm volatile (
  206. * "xxx"
  207. * : "x"(h),
  208. * "y"(l),
  209. * : "z"(h)
  210. * );
  211. */
  212. static void align_asm_colon(void);
  213. static void align_stack(ChunkStack &cs, size_t col, bool align_single, log_sev_t sev)
  214. {
  215. LOG_FUNC_ENTRY();
  216. if (cpd.settings[UO_align_on_tabstop].b)
  217. {
  218. col = align_tab_column(col);
  219. }
  220. if ((cs.Len() > 1) || (align_single && (cs.Len() == 1)))
  221. {
  222. LOG_FMT(sev, "%s: max_col=%zu\n", __func__, col);
  223. chunk_t *pc;
  224. while ((pc = cs.Pop_Back()) != NULL)
  225. {
  226. align_to_column(pc, col);
  227. chunk_flags_set(pc, PCF_WAS_ALIGNED);
  228. LOG_FMT(sev, "%s: indented [%s] on line %zu to %zu\n",
  229. __func__, pc->text(), pc->orig_line, pc->column);
  230. }
  231. }
  232. cs.Reset();
  233. }
  234. /**
  235. * Adds an item to the align stack and adjust the nl_count and max_col.
  236. * Adjust max_col as needed
  237. *
  238. * @param pc the item to add
  239. * @param max_col pointer to the column variable
  240. * @param extra_pad extra padding
  241. */
  242. static void align_add(ChunkStack &cs, chunk_t *pc, size_t &max_col, size_t min_pad, bool squeeze)
  243. {
  244. LOG_FUNC_ENTRY();
  245. size_t min_col;
  246. chunk_t *prev = chunk_get_prev(pc);
  247. if ((prev == NULL) || chunk_is_newline(prev))
  248. {
  249. min_col = squeeze ? 1 : pc->column;
  250. LOG_FMT(LALADD, "%s: pc->orig_line=%zu, pc->col=%zu max_col=%zu min_pad=%zu min_col=%zu\n",
  251. __func__, pc->orig_line, pc->column, max_col, min_pad, min_col);
  252. }
  253. else
  254. {
  255. if (prev->type == CT_COMMENT_MULTI)
  256. {
  257. min_col = prev->orig_col_end + min_pad;
  258. }
  259. else
  260. {
  261. min_col = prev->column + prev->len() + min_pad;
  262. }
  263. if (!squeeze)
  264. {
  265. if (min_col < pc->column)
  266. {
  267. min_col = pc->column;
  268. }
  269. }
  270. LOG_FMT(LALADD, "%s: pc->orig_line=%zu, pc->col=%zu max_col=%zu min_pad=%zu min_col=%zu multi:%s prev->col=%d prev->len()=%zu %s\n",
  271. __func__, pc->orig_line, pc->column, max_col, min_pad, min_col, (prev->type == CT_COMMENT_MULTI) ? "Y" : "N",
  272. (prev->type == CT_COMMENT_MULTI) ? prev->orig_col_end : (UINT32)prev->column, prev->len(), get_token_name(prev->type));
  273. }
  274. if (cs.Empty())
  275. {
  276. max_col = 0;
  277. }
  278. cs.Push_Back(pc);
  279. if (min_col > max_col)
  280. {
  281. max_col = min_col;
  282. }
  283. } // align_add
  284. void quick_align_again(void)
  285. {
  286. LOG_FUNC_ENTRY();
  287. LOG_FMT(LALAGAIN, "%s:\n", __func__);
  288. for (chunk_t *pc = chunk_get_head(); pc != NULL; pc = chunk_get_next(pc))
  289. {
  290. if ((pc->align.next != NULL) && (pc->flags & PCF_ALIGN_START))
  291. {
  292. AlignStack as;
  293. as.Start(100, 0);
  294. as.m_right_align = pc->align.right_align;
  295. as.m_star_style = (AlignStack::StarStyle)pc->align.star_style;
  296. as.m_amp_style = (AlignStack::StarStyle)pc->align.amp_style;
  297. as.m_gap = pc->align.gap;
  298. LOG_FMT(LALAGAIN, " [%s:%zu]", pc->text(), pc->orig_line);
  299. as.Add(pc->align.start);
  300. chunk_flags_set(pc, PCF_WAS_ALIGNED);
  301. for (chunk_t *tmp = pc->align.next; tmp != NULL; tmp = tmp->align.next)
  302. {
  303. chunk_flags_set(tmp, PCF_WAS_ALIGNED);
  304. as.Add(tmp->align.start);
  305. LOG_FMT(LALAGAIN, " => [%s:%zu]", tmp->text(), tmp->orig_line);
  306. }
  307. LOG_FMT(LALAGAIN, "\n");
  308. as.End();
  309. }
  310. }
  311. }
  312. void quick_indent_again(void)
  313. {
  314. LOG_FUNC_ENTRY();
  315. for (chunk_t *pc = chunk_get_head(); pc; pc = chunk_get_next(pc))
  316. {
  317. if (pc->indent.ref)
  318. {
  319. chunk_t *tmp = chunk_get_prev(pc);
  320. if (chunk_is_newline(tmp))
  321. {
  322. size_t col = pc->indent.ref->column + pc->indent.delta;
  323. indent_to_column(pc, col);
  324. LOG_FMT(LINDENTAG, "%s: [%zu] indent [%s] to %zu based on [%s] @ %zu:%zu\n",
  325. __func__, pc->orig_line, pc->text(), col,
  326. pc->indent.ref->text(),
  327. pc->indent.ref->orig_line, pc->indent.ref->column);
  328. }
  329. }
  330. }
  331. }
  332. void align_all(void)
  333. {
  334. LOG_FUNC_ENTRY();
  335. if (cpd.settings[UO_align_typedef_span].u > 0)
  336. {
  337. align_typedefs(cpd.settings[UO_align_typedef_span].u);
  338. }
  339. if (cpd.settings[UO_align_left_shift].b)
  340. {
  341. align_left_shift();
  342. }
  343. if (cpd.settings[UO_align_oc_msg_colon_span].u > 0)
  344. {
  345. align_oc_msg_colons();
  346. }
  347. /* Align variable definitions */
  348. if ((cpd.settings[UO_align_var_def_span].u > 0) ||
  349. (cpd.settings[UO_align_var_struct_span].u > 0) ||
  350. (cpd.settings[UO_align_var_class_span].u > 0))
  351. {
  352. align_var_def_brace(chunk_get_head(), cpd.settings[UO_align_var_def_span].u, NULL);
  353. }
  354. /* Align assignments */
  355. align_assign(chunk_get_head(),
  356. cpd.settings[UO_align_assign_span].u,
  357. cpd.settings[UO_align_assign_thresh].u);
  358. /* Align structure initializers */
  359. if (cpd.settings[UO_align_struct_init_span].u > 0)
  360. {
  361. align_struct_initializers();
  362. }
  363. /* Align function prototypes */
  364. if ((cpd.settings[UO_align_func_proto_span].u > 0) &&
  365. !cpd.settings[UO_align_mix_var_proto].b)
  366. {
  367. align_func_proto(cpd.settings[UO_align_func_proto_span].u);
  368. }
  369. /* Align function prototypes */
  370. if (cpd.settings[UO_align_oc_msg_spec_span].u > 0)
  371. {
  372. align_oc_msg_spec(cpd.settings[UO_align_oc_msg_spec_span].u);
  373. }
  374. /* Align OC colons */
  375. if (cpd.settings[UO_align_oc_decl_colon].b)
  376. {
  377. align_oc_decl_colon();
  378. }
  379. if (cpd.settings[UO_align_asm_colon].b)
  380. {
  381. align_asm_colon();
  382. }
  383. /* Align variable defs in function prototypes */
  384. if (cpd.settings[UO_align_func_params].b)
  385. {
  386. align_func_params();
  387. }
  388. if (cpd.settings[UO_align_same_func_call_params].b)
  389. {
  390. align_same_func_call_params();
  391. }
  392. /* Just in case something was aligned out of order... do it again */
  393. quick_align_again();
  394. } // align_all
  395. static void align_oc_msg_spec(size_t span)
  396. {
  397. LOG_FUNC_ENTRY();
  398. LOG_FMT(LALIGN, "%s\n", __func__);
  399. AlignStack as;
  400. as.Start(span, 0);
  401. for (chunk_t *pc = chunk_get_head(); pc != NULL; pc = chunk_get_next(pc))
  402. {
  403. if (chunk_is_newline(pc))
  404. {
  405. as.NewLines(pc->nl_count);
  406. }
  407. else if (pc->type == CT_OC_MSG_SPEC)
  408. {
  409. as.Add(pc);
  410. }
  411. }
  412. as.End();
  413. }
  414. void align_backslash_newline(void)
  415. {
  416. LOG_FUNC_ENTRY();
  417. chunk_t *pc = chunk_get_head();
  418. while (pc != NULL)
  419. {
  420. if (pc->type != CT_NL_CONT)
  421. {
  422. pc = chunk_get_next_type(pc, CT_NL_CONT, -1);
  423. continue;
  424. }
  425. pc = align_nl_cont(pc);
  426. }
  427. }
  428. void align_right_comments(void)
  429. {
  430. LOG_FUNC_ENTRY();
  431. for (chunk_t *pc = chunk_get_head(); pc != NULL; pc = chunk_get_next(pc))
  432. {
  433. if ((pc->type == CT_COMMENT) ||
  434. (pc->type == CT_COMMENT_CPP) ||
  435. (pc->type == CT_COMMENT_MULTI))
  436. {
  437. if (pc->parent_type == CT_COMMENT_END)
  438. {
  439. bool skip = false;
  440. chunk_t *prev = chunk_get_prev(pc);
  441. if (pc->orig_col < (prev->orig_col_end + cpd.settings[UO_align_right_cmt_gap].n))
  442. {
  443. // note the use of -5 here (-1 would probably have worked as well) to force
  444. // comments which are stuck to the previous token (gap=0) into alignment with the
  445. // others. Not the major feature, but a nice find. (min_val/max_val in
  446. // options.cpp isn't validated against, it seems; well, I don't mind! :-) )
  447. LOG_FMT(LALTC, "NOT changing END comment on line %zu (%zu <= %d + %d)\n",
  448. pc->orig_line,
  449. pc->orig_col, prev->orig_col_end, cpd.settings[UO_align_right_cmt_gap].n);
  450. skip = true;
  451. }
  452. if (!skip)
  453. {
  454. LOG_FMT(LALTC, "Changing END comment on line %zu into a RIGHT-comment\n",
  455. pc->orig_line);
  456. chunk_flags_set(pc, PCF_RIGHT_COMMENT);
  457. }
  458. }
  459. /* Change certain WHOLE comments into RIGHT-alignable comments */
  460. if (pc->parent_type == CT_COMMENT_WHOLE)
  461. {
  462. size_t max_col = pc->column_indent + cpd.settings[UO_input_tab_size].u;
  463. /* If the comment is further right than the brace level... */
  464. if (pc->column >= max_col)
  465. {
  466. LOG_FMT(LALTC, "Changing WHOLE comment on line %zu into a RIGHT-comment (col=%zu col_ind=%zu max_col=%zu)\n",
  467. pc->orig_line, pc->column, pc->column_indent, max_col);
  468. chunk_flags_set(pc, PCF_RIGHT_COMMENT);
  469. }
  470. }
  471. }
  472. }
  473. chunk_t *pc = chunk_get_head();
  474. while (pc != NULL)
  475. {
  476. if (pc->flags & PCF_RIGHT_COMMENT)
  477. {
  478. pc = align_trailing_comments(pc);
  479. }
  480. else
  481. {
  482. pc = chunk_get_next(pc);
  483. }
  484. }
  485. } // align_right_comments
  486. void align_struct_initializers(void)
  487. {
  488. LOG_FUNC_ENTRY();
  489. chunk_t *pc = chunk_get_head();
  490. while (pc != NULL)
  491. {
  492. chunk_t *prev = chunk_get_prev_ncnl(pc);
  493. if ((prev != NULL) && (prev->type == CT_ASSIGN) &&
  494. ((pc->type == CT_BRACE_OPEN) ||
  495. ((cpd.lang_flags & LANG_D) && (pc->type == CT_SQUARE_OPEN))))
  496. {
  497. align_init_brace(pc);
  498. }
  499. pc = chunk_get_next_type(pc, CT_BRACE_OPEN, -1);
  500. }
  501. }
  502. void align_preprocessor(void)
  503. {
  504. LOG_FUNC_ENTRY();
  505. AlignStack as; // value macros
  506. as.Start(cpd.settings[UO_align_pp_define_span].u);
  507. as.m_gap = cpd.settings[UO_align_pp_define_gap].u;
  508. AlignStack *cur_as = &as;
  509. AlignStack asf; // function macros
  510. asf.Start(cpd.settings[UO_align_pp_define_span].u);
  511. asf.m_gap = cpd.settings[UO_align_pp_define_gap].u;
  512. chunk_t *pc = chunk_get_head();
  513. while (pc != NULL)
  514. {
  515. /* Note: not counting back-slash newline combos */
  516. if (pc->type == CT_NEWLINE)
  517. {
  518. as.NewLines(pc->nl_count);
  519. asf.NewLines(pc->nl_count);
  520. }
  521. /* If we aren't on a 'define', then skip to the next non-comment */
  522. if (pc->type != CT_PP_DEFINE)
  523. {
  524. pc = chunk_get_next_nc(pc);
  525. continue;
  526. }
  527. /* step past the 'define' */
  528. pc = chunk_get_next_nc(pc);
  529. if (pc == NULL)
  530. {
  531. break;
  532. }
  533. LOG_FMT(LALPP, "%s: define (%s) on line %zu col %zu\n",
  534. __func__, pc->text(), pc->orig_line, pc->orig_col);
  535. cur_as = &as;
  536. if (pc->type == CT_MACRO_FUNC)
  537. {
  538. if (!cpd.settings[UO_align_pp_define_together].b)
  539. {
  540. cur_as = &asf;
  541. }
  542. /* Skip to the close paren */
  543. pc = chunk_get_next_nc(pc); // point to open (
  544. pc = chunk_get_next_type(pc, CT_FPAREN_CLOSE, pc->level);
  545. LOG_FMT(LALPP, "%s: jumped to (%s) on line %zu col %zu\n",
  546. __func__, pc->text(), pc->orig_line, pc->orig_col);
  547. }
  548. /* step to the value past the close paren or the macro name */
  549. pc = chunk_get_next(pc);
  550. if (pc == NULL)
  551. {
  552. break;
  553. }
  554. /* don't align anything if the first line ends with a newline before
  555. * a value is given */
  556. if (!chunk_is_newline(pc))
  557. {
  558. LOG_FMT(LALPP, "%s: align on '%s', line %zu col %zu\n",
  559. __func__, pc->text(), pc->orig_line, pc->orig_col);
  560. cur_as->Add(pc);
  561. }
  562. }
  563. as.End();
  564. asf.End();
  565. } // align_preprocessor
  566. chunk_t *align_assign(chunk_t *first, size_t span, size_t thresh)
  567. {
  568. LOG_FUNC_ENTRY();
  569. if (first == NULL)
  570. {
  571. return(NULL);
  572. }
  573. size_t my_level = first->level;
  574. if (span == 0)
  575. {
  576. return(chunk_get_next(first));
  577. }
  578. LOG_FMT(LALASS, "%s[%zu]: checking %s on line %zu - span=%zu thresh=%zu\n",
  579. __func__, my_level, first->text(), first->orig_line, span, thresh);
  580. /* If we are aligning on a tabstop, we shouldn't right-align */
  581. AlignStack as; // regular assigns
  582. as.Start(span, thresh);
  583. as.m_right_align = !cpd.settings[UO_align_on_tabstop].b;
  584. AlignStack vdas; // variable def assigns
  585. vdas.Start(span, thresh);
  586. vdas.m_right_align = as.m_right_align;
  587. size_t var_def_cnt = 0;
  588. size_t equ_count = 0;
  589. size_t tmp;
  590. chunk_t *pc = first;
  591. while ((pc != NULL) && ((pc->level >= my_level) || (pc->level == 0)))
  592. {
  593. /* Don't check inside PAREN or SQUARE groups */
  594. if ((pc->type == CT_SPAREN_OPEN) ||
  595. (pc->type == CT_FPAREN_OPEN) ||
  596. (pc->type == CT_SQUARE_OPEN) ||
  597. (pc->type == CT_PAREN_OPEN))
  598. {
  599. tmp = pc->orig_line;
  600. pc = chunk_skip_to_match(pc);
  601. if (pc != NULL)
  602. {
  603. as.NewLines(pc->orig_line - tmp);
  604. vdas.NewLines(pc->orig_line - tmp);
  605. }
  606. continue;
  607. }
  608. /* Recurse if a brace set is found */
  609. if ((pc->type == CT_BRACE_OPEN) ||
  610. (pc->type == CT_VBRACE_OPEN))
  611. {
  612. size_t myspan;
  613. size_t mythresh;
  614. tmp = pc->orig_line;
  615. if (pc->parent_type == CT_ENUM)
  616. {
  617. myspan = cpd.settings[UO_align_enum_equ_span].u;
  618. mythresh = cpd.settings[UO_align_enum_equ_thresh].u;
  619. }
  620. else
  621. {
  622. myspan = cpd.settings[UO_align_assign_span].u;
  623. mythresh = cpd.settings[UO_align_assign_thresh].u;
  624. }
  625. pc = align_assign(chunk_get_next_ncnl(pc), myspan, mythresh);
  626. if (pc != NULL)
  627. {
  628. /* do a rough count of the number of lines just spanned */
  629. as.NewLines(pc->orig_line - tmp);
  630. vdas.NewLines(pc->orig_line - tmp);
  631. }
  632. continue;
  633. }
  634. if (chunk_is_newline(pc))
  635. {
  636. as.NewLines(pc->nl_count);
  637. vdas.NewLines(pc->nl_count);
  638. var_def_cnt = 0;
  639. equ_count = 0;
  640. }
  641. else if (pc->flags & PCF_VAR_DEF)
  642. {
  643. var_def_cnt++;
  644. }
  645. else if (var_def_cnt > 1)
  646. {
  647. /* we hit the second variable def - don't look for assigns, don't align */
  648. vdas.Reset();
  649. }
  650. else if ((equ_count == 0) && (pc->type == CT_ASSIGN))
  651. {
  652. //fprintf(stderr, "%s: ** %s level=%d line=%zu col=%d prev=%d count=%d\n",
  653. // __func__, pc->str, pc->level, pc->orig_line, pc->orig_col, prev_equ_type,
  654. // equ_count);
  655. equ_count++;
  656. if (var_def_cnt != 0)
  657. {
  658. vdas.Add(pc);
  659. }
  660. else
  661. {
  662. as.Add(pc);
  663. }
  664. }
  665. pc = chunk_get_next(pc);
  666. }
  667. as.End();
  668. vdas.End();
  669. if (pc != NULL)
  670. {
  671. LOG_FMT(LALASS, "%s: done on %s on line %zu\n",
  672. __func__, pc->text(), pc->orig_line);
  673. }
  674. else
  675. {
  676. LOG_FMT(LALASS, "%s: done on NULL\n", __func__);
  677. }
  678. return(pc);
  679. } // align_assign
  680. static chunk_t *align_func_param(chunk_t *start)
  681. {
  682. LOG_FUNC_ENTRY();
  683. AlignStack as;
  684. as.Start(2, 0);
  685. as.m_star_style = (AlignStack::StarStyle)cpd.settings[UO_align_var_def_star_style].u;
  686. as.m_amp_style = (AlignStack::StarStyle)cpd.settings[UO_align_var_def_amp_style].u;
  687. bool did_this_line = false;
  688. size_t comma_count = 0;
  689. size_t chunk_count = 0;
  690. chunk_t *pc = start;
  691. while ((pc = chunk_get_next(pc)) != NULL)
  692. {
  693. chunk_count++;
  694. if (chunk_is_newline(pc))
  695. {
  696. did_this_line = false;
  697. comma_count = 0;
  698. chunk_count = 0;
  699. }
  700. else if (pc->level <= start->level)
  701. {
  702. break;
  703. }
  704. else if (!did_this_line && (pc->flags & PCF_VAR_DEF))
  705. {
  706. if (chunk_count > 1)
  707. {
  708. as.Add(pc);
  709. }
  710. did_this_line = true;
  711. }
  712. else if (comma_count > 0)
  713. {
  714. if (!chunk_is_comment(pc))
  715. {
  716. comma_count = 2;
  717. break;
  718. }
  719. }
  720. else if (pc->type == CT_COMMA)
  721. {
  722. comma_count++;
  723. }
  724. }
  725. if (comma_count <= 1)
  726. {
  727. as.End();
  728. }
  729. return(pc);
  730. } // align_func_param
  731. static void align_func_params(void)
  732. {
  733. LOG_FUNC_ENTRY();
  734. chunk_t *pc = chunk_get_head();
  735. while ((pc = chunk_get_next(pc)) != NULL)
  736. {
  737. if ((pc->type != CT_FPAREN_OPEN) ||
  738. ((pc->parent_type != CT_FUNC_PROTO) &&
  739. (pc->parent_type != CT_FUNC_DEF) &&
  740. (pc->parent_type != CT_FUNC_CLASS_PROTO) &&
  741. (pc->parent_type != CT_FUNC_CLASS_DEF) &&
  742. (pc->parent_type != CT_TYPEDEF)))
  743. {
  744. continue;
  745. }
  746. /* We're on a open paren of a prototype */
  747. pc = align_func_param(pc);
  748. }
  749. }
  750. static void align_params(chunk_t *start, deque<chunk_t *> &chunks)
  751. {
  752. LOG_FUNC_ENTRY();
  753. chunks.clear();
  754. bool hit_comma = true;
  755. chunk_t *pc = chunk_get_next_type(start, CT_FPAREN_OPEN, start->level);
  756. while ((pc = chunk_get_next(pc)) != NULL)
  757. {
  758. if (chunk_is_newline(pc) ||
  759. (pc->type == CT_SEMICOLON) ||
  760. ((pc->type == CT_FPAREN_CLOSE) && (pc->level == start->level)))
  761. {
  762. break;
  763. }
  764. if (pc->level == (start->level + 1))
  765. {
  766. if (hit_comma)
  767. {
  768. chunks.push_back(pc);
  769. hit_comma = false;
  770. }
  771. else if (pc->type == CT_COMMA)
  772. {
  773. hit_comma = true;
  774. }
  775. }
  776. }
  777. }
  778. static void align_same_func_call_params(void)
  779. {
  780. LOG_FUNC_ENTRY();
  781. chunk_t *pc;
  782. chunk_t *align_root = NULL;
  783. chunk_t *align_cur = NULL;
  784. size_t align_len = 0;
  785. chunk_t *align_fcn;
  786. unc_text align_fcn_name;
  787. unc_text align_root_name;
  788. deque<chunk_t *> chunks;
  789. deque<AlignStack> as;
  790. AlignStack fcn_as;
  791. const char *add_str;
  792. fcn_as.Start(3);
  793. for (pc = chunk_get_head(); pc != NULL; pc = chunk_get_next(pc))
  794. {
  795. if (pc->type != CT_FUNC_CALL)
  796. {
  797. if (chunk_is_newline(pc))
  798. {
  799. for (size_t idx = 0; idx < as.size(); idx++)
  800. {
  801. as[idx].NewLines(pc->nl_count);
  802. }
  803. fcn_as.NewLines(pc->nl_count);
  804. }
  805. else
  806. {
  807. /* if we drop below the brace level that started it, we are done */
  808. if (align_root && (align_root->brace_level > pc->brace_level))
  809. {
  810. LOG_FMT(LASFCP, " ++ (drop) Ended with %zu fcns\n", align_len);
  811. /* Flush it all! */
  812. fcn_as.Flush();
  813. for (size_t idx = 0; idx < as.size(); idx++)
  814. {
  815. as[idx].Flush();
  816. }
  817. align_root = NULL;
  818. }
  819. }
  820. continue;
  821. }
  822. /* Only align function calls that are right after a newline */
  823. chunk_t *prev = chunk_get_prev(pc);
  824. while (chunk_is_token(prev, CT_MEMBER) || chunk_is_token(prev, CT_DC_MEMBER))
  825. {
  826. chunk_t *tprev = chunk_get_prev(prev);
  827. if (!chunk_is_token(tprev, CT_TYPE))
  828. {
  829. prev = tprev;
  830. break;
  831. }
  832. prev = chunk_get_prev(tprev);
  833. }
  834. if (!chunk_is_newline(prev))
  835. {
  836. continue;
  837. }
  838. prev = chunk_get_next(prev);
  839. align_fcn = prev;
  840. align_fcn_name.clear();
  841. LOG_FMT(LASFCP, "(%d) align_fnc_name [%s]\n", __LINE__, align_fcn_name.c_str());
  842. while (prev != pc)
  843. {
  844. LOG_FMT(LASFCP, "(%d) align_fnc_name [%s]\n", __LINE__, align_fcn_name.c_str());
  845. align_fcn_name += prev->str;
  846. LOG_FMT(LASFCP, "(%d) align_fnc_name [%s]\n", __LINE__, align_fcn_name.c_str());
  847. prev = chunk_get_next(prev);
  848. }
  849. LOG_FMT(LASFCP, "(%d) align_fnc_name [%s]\n", __LINE__, align_fcn_name.c_str());
  850. align_fcn_name += pc->str;
  851. LOG_FMT(LASFCP, "(%d) align_fnc_name [%s]\n", __LINE__, align_fcn_name.c_str());
  852. LOG_FMT(LASFCP, "Func Call @ %zu:%zu [%s]\n",
  853. align_fcn->orig_line,
  854. align_fcn->orig_col,
  855. align_fcn_name.c_str());
  856. add_str = NULL;
  857. if (align_root != NULL)
  858. {
  859. /* can only align functions on the same brace level */
  860. if ((align_root->brace_level == pc->brace_level) &&
  861. align_fcn_name.equals(align_root_name))
  862. {
  863. fcn_as.Add(pc);
  864. align_cur->align.next = pc;
  865. align_cur = pc;
  866. align_len++;
  867. add_str = " Add";
  868. }
  869. else
  870. {
  871. LOG_FMT(LASFCP, " ++ Ended with %zu fcns\n", align_len);
  872. /* Flush it all! */
  873. fcn_as.Flush();
  874. for (size_t idx = 0; idx < as.size(); idx++)
  875. {
  876. as[idx].Flush();
  877. }
  878. align_root = NULL;
  879. }
  880. }
  881. if (align_root == NULL)
  882. {
  883. fcn_as.Add(pc);
  884. align_root = align_fcn;
  885. align_root_name = align_fcn_name;
  886. align_cur = pc;
  887. align_len = 1;
  888. add_str = "Start";
  889. }
  890. if (add_str != NULL)
  891. {
  892. LOG_FMT(LASFCP, "%s '%s' on line %zu -",
  893. add_str, align_fcn_name.c_str(), pc->orig_line);
  894. align_params(pc, chunks);
  895. LOG_FMT(LASFCP, " %d items:", (int)chunks.size());
  896. for (size_t idx = 0; idx < chunks.size(); idx++)
  897. {
  898. LOG_FMT(LASFCP, " [%s]", chunks[idx]->text());
  899. if (idx >= as.size())
  900. {
  901. as.resize(idx + 1);
  902. as[idx].Start(3);
  903. if (!cpd.settings[UO_align_number_left].b)
  904. {
  905. if ((chunks[idx]->type == CT_NUMBER_FP) ||
  906. (chunks[idx]->type == CT_NUMBER) ||
  907. (chunks[idx]->type == CT_POS) ||
  908. (chunks[idx]->type == CT_NEG))
  909. {
  910. as[idx].m_right_align = !cpd.settings[UO_align_on_tabstop].b;
  911. }
  912. }
  913. }
  914. as[idx].Add(chunks[idx]);
  915. }
  916. LOG_FMT(LASFCP, "\n");
  917. }
  918. }
  919. if (align_len > 1)
  920. {
  921. LOG_FMT(LASFCP, " ++ Ended with %zu fcns\n", align_len);
  922. fcn_as.End();
  923. for (size_t idx = 0; idx < as.size(); idx++)
  924. {
  925. as[idx].End();
  926. }
  927. }
  928. } // align_same_func_call_params
  929. chunk_t *step_back_over_member(chunk_t *pc)
  930. {
  931. chunk_t *tmp;
  932. /* Skip over any class stuff: bool CFoo::bar() */
  933. while (((tmp = chunk_get_prev_ncnl(pc)) != NULL) &&
  934. (tmp->type == CT_DC_MEMBER))
  935. {
  936. /* TODO: verify that we are pointing at something sane? */
  937. pc = chunk_get_prev_ncnl(tmp);
  938. }
  939. return(pc);
  940. }
  941. static void align_func_proto(size_t span)
  942. {
  943. LOG_FUNC_ENTRY();
  944. LOG_FMT(LALIGN, "%s\n", __func__);
  945. AlignStack as;
  946. as.Start(span, 0);
  947. as.m_gap = cpd.settings[UO_align_func_proto_gap].u;
  948. as.m_star_style = (AlignStack::StarStyle)cpd.settings[UO_align_var_def_star_style].u;
  949. as.m_amp_style = (AlignStack::StarStyle)cpd.settings[UO_align_var_def_amp_style].u;
  950. AlignStack as_br;
  951. as_br.Start(span, 0);
  952. as_br.m_gap = cpd.settings[UO_align_single_line_brace_gap].u;
  953. bool look_bro = false;
  954. chunk_t *toadd;
  955. for (chunk_t *pc = chunk_get_head(); pc != NULL; pc = chunk_get_next(pc))
  956. {
  957. if (chunk_is_newline(pc))
  958. {
  959. look_bro = false;
  960. as.NewLines(pc->nl_count);
  961. as_br.NewLines(pc->nl_count);
  962. }
  963. else if ((pc->type == CT_FUNC_PROTO) ||
  964. ((pc->type == CT_FUNC_DEF) &&
  965. cpd.settings[UO_align_single_line_func].b))
  966. {
  967. if ((pc->parent_type == CT_OPERATOR) &&
  968. cpd.settings[UO_align_on_operator].b)
  969. {
  970. toadd = chunk_get_prev_ncnl(pc);
  971. }
  972. else
  973. {
  974. toadd = pc;
  975. }
  976. as.Add(step_back_over_member(toadd));
  977. look_bro = (pc->type == CT_FUNC_DEF) &&
  978. cpd.settings[UO_align_single_line_brace].b;
  979. }
  980. else if (look_bro &&
  981. (pc->type == CT_BRACE_OPEN) &&
  982. (pc->flags & PCF_ONE_LINER))
  983. {
  984. as_br.Add(pc);
  985. look_bro = false;
  986. }
  987. }
  988. as.End();
  989. as_br.End();
  990. } // align_func_proto
  991. static chunk_t *align_var_def_brace(chunk_t *start, size_t span, size_t *p_nl_count)
  992. {
  993. LOG_FUNC_ENTRY();
  994. if (start == NULL)
  995. {
  996. return(NULL);
  997. }
  998. chunk_t *next;
  999. size_t myspan = span;
  1000. size_t mythresh = 0;
  1001. size_t mygap = 0;
  1002. /* Override the span, if this is a struct/union */
  1003. if ((start->parent_type == CT_STRUCT) ||
  1004. (start->parent_type == CT_UNION))
  1005. {
  1006. myspan = cpd.settings[UO_align_var_struct_span].u;
  1007. mythresh = cpd.settings[UO_align_var_struct_thresh].u;
  1008. mygap = cpd.settings[UO_align_var_struct_gap].u;
  1009. }
  1010. else if (start->parent_type == CT_CLASS)
  1011. {
  1012. myspan = cpd.settings[UO_align_var_class_span].u;
  1013. mythresh = cpd.settings[UO_align_var_class_thresh].u;
  1014. mygap = cpd.settings[UO_align_var_class_gap].u;
  1015. }
  1016. else
  1017. {
  1018. mythresh = cpd.settings[UO_align_var_def_thresh].u;
  1019. mygap = cpd.settings[UO_align_var_def_gap].u;
  1020. }
  1021. /* can't be any variable definitions in a "= {" block */
  1022. chunk_t *prev = chunk_get_prev_ncnl(start);
  1023. if ((prev != NULL) && (prev->type == CT_ASSIGN))
  1024. {
  1025. LOG_FMT(LAVDB, "%s: start=%s [%s] on line %zu (abort due to assign)\n", __func__,
  1026. start->text(), get_token_name(start->type), start->orig_line);
  1027. chunk_t *pc = chunk_get_next_type(start, CT_BRACE_CLOSE, start->level);
  1028. return(chunk_get_next_ncnl(pc));
  1029. }
  1030. LOG_FMT(LAVDB, "%s: start=%s [%s] on line %zu\n", __func__,
  1031. start->text(), get_token_name(start->type), start->orig_line);
  1032. UINT64 align_mask = PCF_IN_FCN_DEF | PCF_VAR_1ST;
  1033. if (!cpd.settings[UO_align_var_def_inline].b)
  1034. {
  1035. align_mask |= PCF_VAR_INLINE;
  1036. }
  1037. /* Set up the var/proto/def aligner */
  1038. AlignStack as;
  1039. as.Start(myspan, mythresh);
  1040. as.m_gap = mygap;
  1041. as.m_star_style = (AlignStack::StarStyle)cpd.settings[UO_align_var_def_star_style].u;
  1042. as.m_amp_style = (AlignStack::StarStyle)cpd.settings[UO_align_var_def_amp_style].u;
  1043. /* Set up the bit colon aligner */
  1044. AlignStack as_bc;
  1045. as_bc.Start(myspan, 0);
  1046. as_bc.m_gap = cpd.settings[UO_align_var_def_colon_gap].n;
  1047. AlignStack as_at; /* attribute */
  1048. as_at.Start(myspan, 0);
  1049. /* Set up the brace open aligner */
  1050. AlignStack as_br;
  1051. as_br.Start(myspan, mythresh);
  1052. as_br.m_gap = cpd.settings[UO_align_single_line_brace_gap].u;
  1053. bool fp_look_bro = false;
  1054. bool did_this_line = false;
  1055. bool fp_active = cpd.settings[UO_align_mix_var_proto].b;
  1056. chunk_t *pc = chunk_get_next(start);
  1057. while ((pc != NULL) && ((pc->level >= start->level) || (pc->level == 0)))
  1058. {
  1059. LOG_FMT(LGUY, "%s: pc->text()=%s, pc->orig_line=%zu, pc->orig_col=%zu\n",
  1060. __func__, pc->text(), pc->orig_line, pc->orig_col);
  1061. if (chunk_is_comment(pc))
  1062. {
  1063. if (pc->nl_count > 0)
  1064. {
  1065. as.NewLines(pc->nl_count);
  1066. as_bc.NewLines(pc->nl_count);
  1067. as_at.NewLines(pc->nl_count);
  1068. as_br.NewLines(pc->nl_count);
  1069. }
  1070. pc = chunk_get_next(pc);
  1071. continue;
  1072. }
  1073. if (fp_active && !(pc->flags & PCF_IN_CLASS_BASE))
  1074. {
  1075. if ((pc->type == CT_FUNC_PROTO) ||
  1076. ((pc->type == CT_FUNC_DEF) &&
  1077. cpd.settings[UO_align_single_line_func].b))
  1078. {
  1079. LOG_FMT(LAVDB, " add=[%s] line=%zu col=%zu level=%zu\n",
  1080. pc->text(), pc->orig_line, pc->orig_col, pc->level);
  1081. as.Add(pc);
  1082. fp_look_bro = (pc->type == CT_FUNC_DEF) &&
  1083. cpd.settings[UO_align_single_line_brace].b;
  1084. }
  1085. else if (fp_look_bro &&
  1086. (pc->type == CT_BRACE_OPEN) &&
  1087. (pc->flags & PCF_ONE_LINER))
  1088. {
  1089. as_br.Add(pc);
  1090. fp_look_bro = false;
  1091. }
  1092. }
  1093. /* process nested braces */
  1094. if (pc->type == CT_BRACE_OPEN)
  1095. {
  1096. size_t sub_nl_count = 0;
  1097. pc = align_var_def_brace(pc, span, &sub_nl_count);
  1098. if (sub_nl_count > 0)
  1099. {
  1100. fp_look_bro = false;
  1101. did_this_line = false;
  1102. as.NewLines(sub_nl_count);
  1103. as_bc.NewLines(sub_nl_count);
  1104. as_at.NewLines(sub_nl_count);
  1105. as_br.NewLines(sub_nl_count);
  1106. if (p_nl_count != NULL)
  1107. {
  1108. *p_nl_count += sub_nl_count;
  1109. }
  1110. }
  1111. continue;
  1112. }
  1113. /* Done with this brace set? */
  1114. if (pc->type == CT_BRACE_CLOSE)
  1115. {
  1116. pc = chunk_get_next(pc);
  1117. break;
  1118. }
  1119. if (chunk_is_newline(pc))
  1120. {
  1121. fp_look_bro = false;
  1122. did_this_line = false;
  1123. as.NewLines(pc->nl_count);
  1124. as_bc.NewLines(pc->nl_count);
  1125. as_at.NewLines(pc->nl_count);
  1126. as_br.NewLines(pc->nl_count);
  1127. if (p_nl_count != NULL)
  1128. {
  1129. *p_nl_count += pc->nl_count;
  1130. }
  1131. }
  1132. /* don't align stuff inside parens/squares/angles */
  1133. if (pc->level > pc->brace_level)
  1134. {
  1135. pc = chunk_get_next(pc);
  1136. continue;
  1137. }
  1138. /* If this is a variable def, update the max_col */
  1139. if (!(pc->flags & PCF_IN_CLASS_BASE) &&
  1140. (pc->type != CT_FUNC_CLASS_DEF) &&
  1141. (pc->type != CT_FUNC_CLASS_PROTO) &&
  1142. ((pc->flags & align_mask) == PCF_VAR_1ST) &&
  1143. ((pc->level == (start->level + 1)) ||
  1144. (pc->level == 0)) &&
  1145. pc->prev && (pc->prev->type != CT_MEMBER))
  1146. {
  1147. if (!did_this_line)
  1148. {
  1149. if ((start->parent_type == CT_STRUCT) &&
  1150. (as.m_star_style == AlignStack::SS_INCLUDE))
  1151. {
  1152. // we must look after the previous token
  1153. chunk_t *prev_local = pc->prev;
  1154. while ((prev_local->type == CT_PTR_TYPE) ||
  1155. (prev_local->type == CT_ADDR))
  1156. {
  1157. LOG_FMT(LAVDB, " prev_local=%s, prev_local->type=%s\n",
  1158. prev_local->text(), get_token_name(prev_local->type));
  1159. prev_local = prev_local->prev;
  1160. }
  1161. pc = prev_local->next;
  1162. }
  1163. LOG_FMT(LAVDB, " add=[%s] line=%zu col=%zu level=%zu\n",
  1164. pc->text(), pc->orig_line, pc->orig_col, pc->level);
  1165. as.Add(step_back_over_member(pc));
  1166. if (cpd.settings[UO_align_var_def_colon].b)
  1167. {
  1168. next = chunk_get_next_nc(pc);
  1169. if (next->type == CT_BIT_COLON)
  1170. {
  1171. as_bc.Add(next);
  1172. }
  1173. }
  1174. if (cpd.settings[UO_align_var_def_attribute].b)
  1175. {
  1176. next = pc;
  1177. while ((next = chunk_get_next_nc(next)) != NULL)
  1178. {
  1179. if (next->type == CT_ATTRIBUTE)
  1180. {
  1181. as_at.Add(next);
  1182. break;
  1183. }
  1184. if ((next->type == CT_SEMICOLON) || chunk_is_newline(next))
  1185. {
  1186. break;
  1187. }
  1188. }
  1189. }
  1190. }
  1191. did_this_line = true;
  1192. }
  1193. else if (pc->type == CT_BIT_COLON)
  1194. {
  1195. if (!did_this_line)
  1196. {
  1197. as_bc.Add(pc);
  1198. did_this_line = true;
  1199. }
  1200. }
  1201. pc = chunk_get_next(pc);
  1202. }
  1203. as.End();
  1204. as_bc.End();
  1205. as_at.End();
  1206. as_br.End();
  1207. return(pc);
  1208. } // align_var_def_brace
  1209. chunk_t *align_nl_cont(chunk_t *start)
  1210. {
  1211. LOG_FUNC_ENTRY();
  1212. LOG_FMT(LALNLC, "%s: start on [%s] on line %zu\n", __func__,
  1213. get_token_name(start->type), start->orig_line);
  1214. /* Find the max column */
  1215. ChunkStack cs;
  1216. size_t max_col = 0;
  1217. chunk_t *pc = start;
  1218. while ((pc != NULL) &&
  1219. (pc->type != CT_NEWLINE) &&
  1220. (pc->type != CT_COMMENT_MULTI))
  1221. {
  1222. if (pc->type == CT_NL_CONT)
  1223. {
  1224. align_add(cs, pc, max_col, 1, true);
  1225. }
  1226. pc = chunk_get_next(pc);
  1227. }
  1228. /* NL_CONT is always the last thing on a line */
  1229. chunk_t *tmp;
  1230. while ((tmp = cs.Pop_Back()) != NULL)
  1231. {
  1232. chunk_flags_set(tmp, PCF_WAS_ALIGNED);
  1233. tmp->column = max_col;
  1234. }
  1235. return(pc);
  1236. }
  1237. enum CmtAlignType
  1238. {
  1239. CAT_REGULAR,
  1240. CAT_BRACE,
  1241. CAT_ENDIF,
  1242. };
  1243. static CmtAlignType get_comment_align_type(chunk_t *cmt)
  1244. {
  1245. chunk_t *prev;
  1246. CmtAlignType cmt_type = CAT_REGULAR;
  1247. if (!cpd.settings[UO_align_right_cmt_mix].b &&
  1248. ((prev = chunk_get_prev(cmt)) != NULL))
  1249. {
  1250. if ((prev->type == CT_PP_ENDIF) ||
  1251. (prev->type == CT_PP_ELSE) ||
  1252. (prev->type == CT_ELSE) ||
  1253. (prev->type == CT_BRACE_CLOSE))
  1254. {
  1255. /* REVISIT: someone may want this configurable */
  1256. if ((cmt->column - (prev->column + prev->len())) < 3)
  1257. {
  1258. cmt_type = (prev->type == CT_PP_ENDIF) ? CAT_ENDIF : CAT_BRACE;
  1259. }
  1260. }
  1261. }
  1262. return(cmt_type);
  1263. }
  1264. chunk_t *align_trailing_comments(chunk_t *start)
  1265. {
  1266. LOG_FUNC_ENTRY();
  1267. size_t min_col = 0;
  1268. size_t min_orig = 0;
  1269. chunk_t *pc = start;
  1270. size_t nl_count = 0;
  1271. ChunkStack cs;
  1272. size_t col;
  1273. size_t intended_col = cpd.settings[UO_align_right_cmt_at_col].u;
  1274. CmtAlignType cmt_type_cur;
  1275. CmtAlignType cmt_type_start = get_comment_align_type(pc);
  1276. LOG_FMT(LALADD, "%s: start on line=%zu\n",
  1277. __func__, pc->orig_line);
  1278. /* Find the max column */
  1279. while ((pc != NULL) && (nl_count < cpd.settings[UO_align_right_cmt_span].u))
  1280. {
  1281. if ((pc->flags & PCF_RIGHT_COMMENT) && (pc->column > 1))
  1282. {
  1283. cmt_type_cur = get_comment_align_type(pc);
  1284. if (cmt_type_cur == cmt_type_start)
  1285. {
  1286. col = 1 + (pc->brace_level * cpd.settings[UO_indent_columns].u);
  1287. LOG_FMT(LALADD, "%s: line=%zu col=%zu min_col=%zu pc->col=%zu pc->len=%zu %s\n",
  1288. __func__, pc->orig_line, col, min_col, pc->column, pc->len(),
  1289. get_token_name(pc->type));
  1290. if ((min_orig == 0) || (min_orig > pc->column))
  1291. {
  1292. min_orig = pc->column;
  1293. }
  1294. if (pc->column < col)
  1295. {
  1296. pc->column = col;
  1297. }
  1298. align_add(cs, pc, min_col, 1, true); // (intended_col < col));
  1299. nl_count = 0;
  1300. }
  1301. }
  1302. if (chunk_is_newline(pc))
  1303. {
  1304. nl_count += pc->nl_count;
  1305. }
  1306. pc = chunk_get_next(pc);
  1307. }
  1308. /* Start with the minimum original column */
  1309. col = min_orig;
  1310. /* fall back to the intended column */
  1311. if ((intended_col > 0) && (col > intended_col))
  1312. {
  1313. col = intended_col;
  1314. }
  1315. /* if less than allowed, bump it out */
  1316. if (col < min_col)
  1317. {
  1318. col = min_col;
  1319. }
  1320. /* bump out to the intended column */
  1321. if (col < intended_col)
  1322. {
  1323. col = intended_col;
  1324. }
  1325. LOG_FMT(LALADD, "%s: -- min_orig=%zu intended_col=%zu min_allowed=%zu ==> col=%zu\n",
  1326. __func__, min_orig, intended_col, min_col, col);
  1327. if ((cpd.frag_cols > 0) && (cpd.frag_cols <= col))
  1328. {
  1329. col -= cpd.frag_cols;
  1330. }
  1331. align_stack(cs, col, (intended_col != 0), LALTC);
  1332. return(chunk_get_next(pc));
  1333. } // align_trailing_comments
  1334. /**
  1335. * Shifts out all columns by a certain amount.
  1336. *
  1337. * @param idx The index to start shifting
  1338. * @param num The number of columns to shift
  1339. */
  1340. void ib_shift_out(size_t idx, size_t num)
  1341. {
  1342. while (idx < cpd.al_cnt)
  1343. {
  1344. cpd.al[idx].col += num;
  1345. idx++;
  1346. }
  1347. }
  1348. /**
  1349. * If sq_open is CT_SQUARE_OPEN and the matching close is followed by '=',
  1350. * then return the chunk after the '='. Otherwise, return NULL.
  1351. */
  1352. static chunk_t *skip_c99_array(chunk_t *sq_open)
  1353. {
  1354. if (chunk_is_token(sq_open, CT_SQUARE_OPEN))
  1355. {
  1356. chunk_t *tmp = chunk_get_next_nc(chunk_skip_to_match(sq_open));
  1357. if (chunk_is_token(tmp, CT_ASSIGN))
  1358. {
  1359. return(chunk_get_next_nc(tmp));
  1360. }
  1361. }
  1362. return(NULL);
  1363. }
  1364. /**
  1365. * Scans a line for stuff to align on.
  1366. *
  1367. * We trigger on BRACE_OPEN, FPAREN_OPEN, ASSIGN, and COMMA.
  1368. * We want to align the NEXT item.
  1369. */
  1370. static chunk_t *scan_ib_line(chunk_t *start, bool first_pass)
  1371. {
  1372. UNUSED(first_pass);
  1373. LOG_FUNC_ENTRY();
  1374. chunk_t *prev_match = NULL;
  1375. size_t idx = 0;
  1376. /* Skip past C99 "[xx] =" stuff */
  1377. chunk_t *tmp = skip_c99_array(start);
  1378. if (tmp)
  1379. {
  1380. set_chunk_parent(start, CT_TSQUARE);
  1381. start = tmp;
  1382. cpd.al_c99_array = true;
  1383. }
  1384. chunk_t *pc = start;
  1385. if (pc != NULL)
  1386. {
  1387. LOG_FMT(LSIB, "%s: start=%s col %zu/%zu line %zu\n",
  1388. __func__, get_token_name(pc->type), pc->column, pc->orig_col, pc->orig_line);
  1389. }
  1390. while ((pc != NULL) && !chunk_is_newline(pc) &&
  1391. (pc->level >= start->level))
  1392. {
  1393. //LOG_FMT(LSIB, "%s: '%s' col %d/%d line %zu\n", __func__,
  1394. // pc->text(), pc->column, pc->orig_col, pc->orig_line);
  1395. chunk_t *next = chunk_get_next(pc);
  1396. if ((next == NULL) || chunk_is_comment(next))
  1397. {
  1398. /* do nothing */
  1399. }
  1400. else if ((pc->type == CT_ASSIGN) ||
  1401. (pc->type == CT_BRACE_OPEN) ||
  1402. (pc->type == CT_BRACE_CLOSE) ||
  1403. (pc->type == CT_COMMA))
  1404. {
  1405. size_t token_width = space_col_align(pc, next);
  1406. /*TODO: need to handle missing structure defs? ie NULL vs { ... } ?? */
  1407. /* Is this a new entry? */
  1408. if (idx >= cpd.al_cnt)
  1409. {
  1410. LOG_FMT(LSIB, " - New [%zu] %.2zu/%zu - %10.10s\n",
  1411. idx, pc->column, token_width, get_token_name(pc->type));
  1412. cpd.al[cpd.al_cnt].type = pc->type;
  1413. cpd.al[cpd.al_cnt].col = pc->column;
  1414. cpd.al[cpd.al_cnt].len = token_width;
  1415. cpd.al_cnt++;
  1416. idx++;
  1417. }
  1418. else
  1419. {
  1420. /* expect to match stuff */
  1421. if (cpd.al[idx].type == pc->type)
  1422. {
  1423. LOG_FMT(LSIB, " - Match [%zu] %.2zu/%zu - %10.10s",
  1424. idx, pc->column, token_width, get_token_name(pc->type));
  1425. /* Shift out based on column */
  1426. if (prev_match == NULL)
  1427. {
  1428. if (pc->column > cpd.al[idx].col)
  1429. {
  1430. LOG_FMT(LSIB, " [ pc->col(%zu) > col(%zu) ] ",
  1431. pc->column, cpd.al[idx].col);
  1432. ib_shift_out(idx, pc->column - cpd.al[idx].col);
  1433. cpd.al[idx].col = pc->column;
  1434. }
  1435. }
  1436. else if (idx > 0)
  1437. {
  1438. int min_col_diff = pc->column - prev_match->column;
  1439. int cur_col_diff = cpd.al[idx].col - cpd.al[idx - 1].col;
  1440. if (cur_col_diff < min_col_diff)
  1441. {
  1442. LOG_FMT(LSIB, " [ min_col_diff(%d) > cur_col_diff(%d) ] ",
  1443. min_col_diff, cur_col_diff);
  1444. ib_shift_out(idx, min_col_diff - cur_col_diff);
  1445. }
  1446. }
  1447. LOG_FMT(LSIB, " - now col %zu, len %zu\n", cpd.al[idx].col, cpd.al[idx].len);
  1448. idx++;
  1449. }
  1450. }
  1451. prev_match = pc;
  1452. }
  1453. pc = chunk_get_next_nc(pc);
  1454. }
  1455. return(pc);
  1456. } // scan_ib_line
  1457. static void align_log_al(log_sev_t sev, size_t line)
  1458. {
  1459. if (log_sev_on(sev))
  1460. {
  1461. log_fmt(sev, "%s: line %zu, %zu)",
  1462. __func__, line, cpd.al_cnt);
  1463. for (size_t idx = 0; idx < cpd.al_cnt; idx++)
  1464. {
  1465. log_fmt(sev, " %zu/%zu=%s", cpd.al[idx].col, cpd.al[idx].len,
  1466. get_token_name(cpd.al[idx].type));
  1467. }
  1468. log_fmt(sev, "\n");
  1469. }
  1470. }
  1471. static void align_init_brace(chunk_t *start)
  1472. {
  1473. LOG_FUNC_ENTRY();
  1474. chunk_t *num_token = NULL;
  1475. cpd.al_cnt = 0;
  1476. cpd.al_c99_array = false;
  1477. LOG_FMT(LALBR, "%s: start @ %zu:%zu\n", __func__, start->orig_line, start->orig_col);
  1478. chunk_t *pc = chunk_get_next_ncnl(start);
  1479. pc = scan_ib_line(pc, true);
  1480. if ((pc == NULL) || ((pc->type == CT_BRACE_CLOSE) &&
  1481. (pc->parent_type == CT_ASSIGN)))
  1482. {
  1483. /* single line - nothing to do */
  1484. return;
  1485. }
  1486. do
  1487. {
  1488. pc = scan_ib_line(pc, false);
  1489. /* debug dump the current frame */
  1490. align_log_al(LALBR, pc->orig_line);
  1491. while (chunk_is_newline(pc))
  1492. {
  1493. pc = chunk_get_next(pc);
  1494. }
  1495. } while ((pc != NULL) && (pc->level > start->level));
  1496. /* debug dump the current frame */
  1497. align_log_al(LALBR, start->orig_line);
  1498. if (cpd.settings[UO_align_on_tabstop].b && (cpd.al_cnt >= 1) &&
  1499. (cpd.al[0].type == CT_ASSIGN))
  1500. {
  1501. cpd.al[0].col = align_tab_column(cpd.al[0].col);
  1502. }
  1503. pc = chunk_get_next(start);
  1504. size_t idx = 0;
  1505. do
  1506. {
  1507. chunk_t *tmp;
  1508. if ((idx == 0) && ((tmp = skip_c99_array(pc)) != NULL))
  1509. {
  1510. pc = tmp;
  1511. if (pc)
  1512. {
  1513. LOG_FMT(LALBR, " -%zu- skipped '[] =' to %s\n",
  1514. pc->orig_line, get_token_name(pc->type));
  1515. }
  1516. continue;
  1517. }
  1518. chunk_t *next = pc;
  1519. if (idx < cpd.al_cnt)
  1520. {
  1521. LOG_FMT(LALBR, " (%zu) check %s vs %s -- ",
  1522. idx, get_token_name(pc->type), get_token_name(cpd.al[idx].type));
  1523. if (pc->type == cpd.al[idx].type)
  1524. {
  1525. if ((idx == 0) && cpd.al_c99_array)
  1526. {
  1527. chunk_t *prev = chunk_get_prev(pc);
  1528. if (chunk_is_newline(prev))
  1529. {
  1530. chunk_flags_set(pc, PCF_DONT_INDENT);
  1531. }
  1532. }
  1533. LOG_FMT(LALBR, " [%s] to col %zu\n", pc->text(), cpd.al[idx].col);
  1534. if (num_token != NULL)
  1535. {
  1536. int col_diff = pc->column - num_token->column;
  1537. reindent_line(num_token, cpd.al[idx].col - col_diff);
  1538. //LOG_FMT(LSYS, "-= %zu =- NUM indent [%s] col=%d diff=%d\n",
  1539. // num_token->orig_line,
  1540. // num_token->text(), cpd.al[idx - 1].col, col_diff);
  1541. chunk_flags_set(num_token, PCF_WAS_ALIGNED);
  1542. num_token = NULL;
  1543. }
  1544. /* Comma's need to 'fall back' to the previous token */
  1545. if (pc->type == CT_COMMA)
  1546. {
  1547. next = chunk_get_next(pc);
  1548. if ((next != NULL) && !chunk_is_newline(next))
  1549. {
  1550. //LOG_FMT(LSYS, "-= %zu =- indent [%s] col=%d len=%d\n",
  1551. // next->orig_line,
  1552. // next->text(), cpd.al[idx].col, cpd.al[idx].len);
  1553. if ((idx < (cpd.al_cnt - 1)) &&
  1554. cpd.settings[UO_align_number_left].b &&
  1555. ((next->type == CT_NUMBER_FP) ||
  1556. (next->type == CT_NUMBER) ||
  1557. (next->type == CT_POS) ||
  1558. (next->type == CT_NEG)))
  1559. {
  1560. /* Need to wait until the next match to indent numbers */
  1561. num_token = next;
  1562. }
  1563. else if (idx < (cpd.al_cnt - 1))
  1564. {
  1565. reindent_line(next, cpd.al[idx].col + cpd.al[idx].len);
  1566. chunk_flags_set(next, PCF_WAS_ALIGNED);
  1567. }
  1568. }
  1569. }
  1570. else
  1571. {
  1572. /* first item on the line */
  1573. reindent_line(pc, cpd.al[idx].col);
  1574. chunk_flags_set(pc, PCF_WAS_ALIGNED);
  1575. /* see if we need to right-align a number */
  1576. if ((idx < (cpd.al_cnt - 1)) &&
  1577. cpd.settings[UO_align_number_left].b)
  1578. {
  1579. next = chunk_get_next(pc);
  1580. if ((next != NULL) && !chunk_is_newline(next) &&
  1581. ((next->type == CT_NUMBER_FP) ||
  1582. (next->type == CT_NUMBER) ||
  1583. (next->type == CT_POS) ||
  1584. (next->type == CT_NEG)))
  1585. {
  1586. /* Need to wait until the next match to indent numbers */
  1587. num_token = next;
  1588. }
  1589. }
  1590. }
  1591. idx++;
  1592. }
  1593. else
  1594. {
  1595. LOG_FMT(LALBR, " no match\n");
  1596. }
  1597. }
  1598. if (chunk_is_newline(pc) || chunk_is_newline(next))
  1599. {
  1600. idx = 0;
  1601. }
  1602. pc = chunk_get_next(pc);
  1603. } while ((pc != NULL) && (pc->level > start->level));
  1604. } // align_init_brace
  1605. static void align_typedefs(size_t span)
  1606. {
  1607. LOG_FUNC_ENTRY();
  1608. AlignStack as;
  1609. as.Start(span);
  1610. as.m_gap = cpd.settings[UO_align_typedef_gap].u;
  1611. as.m_star_style = (AlignStack::StarStyle)cpd.settings[UO_align_typedef_star_style].u;
  1612. as.m_amp_style = (AlignStack::StarStyle)cpd.settings[UO_align_typedef_amp_style].u;
  1613. chunk_t *c_typedef = NULL;
  1614. chunk_t *pc = chunk_get_head();
  1615. while (pc != NULL)
  1616. {
  1617. if (chunk_is_newline(pc))
  1618. {
  1619. as.NewLines(pc->nl_count);
  1620. c_typedef = NULL;
  1621. }
  1622. else if (c_typedef != NULL)
  1623. {
  1624. if (pc->flags & PCF_ANCHOR)
  1625. {
  1626. as.Add(pc);
  1627. LOG_FMT(LALTD, "%s: typedef @ %zu:%zu, tag '%s' @ %zu:%zu\n",
  1628. __func__, c_typedef->orig_line, c_typedef->orig_col,
  1629. pc->text(), pc->orig_line, pc->orig_col);
  1630. c_typedef = NULL;
  1631. }
  1632. }
  1633. else
  1634. {
  1635. if (pc->type == CT_TYPEDEF)
  1636. {
  1637. c_typedef = pc;
  1638. }
  1639. }
  1640. pc = chunk_get_next(pc);
  1641. }
  1642. as.End();
  1643. } // align_typedefs
  1644. static void align_left_shift(void)
  1645. {
  1646. LOG_FUNC_ENTRY();
  1647. chunk_t *start = NULL;
  1648. AlignStack as;
  1649. as.Start(255);
  1650. chunk_t *pc = chunk_get_head();
  1651. while (pc != NULL)
  1652. {
  1653. if ((start != NULL) &&
  1654. ((pc->flags & PCF_IN_PREPROC) != (start->flags & PCF_IN_PREPROC)))
  1655. {
  1656. /* a change in preproc status restarts the aligning */
  1657. as.Flush();
  1658. start = NULL;
  1659. }
  1660. else if (chunk_is_newline(pc))
  1661. {
  1662. as.NewLines(pc->nl_count);
  1663. }
  1664. else if ((start != NULL) && (pc->level < start->level))
  1665. {
  1666. /* A drop in level restarts the aligning */
  1667. as.Flush();
  1668. start = NULL;
  1669. }
  1670. else if ((start != NULL) && (pc->level > start->level))
  1671. {
  1672. /* Ignore any deeper levels when aligning */
  1673. }
  1674. else if (pc->type == CT_SEMICOLON)
  1675. {
  1676. /* A semicolon at the same level flushes */
  1677. as.Flush();
  1678. start = NULL;
  1679. }
  1680. else if (!(pc->flags & PCF_IN_ENUM) && chunk_is_str(pc, "<<", 2))
  1681. {
  1682. if (pc->parent_type == CT_OPERATOR)
  1683. {
  1684. /* Ignore operator<< */
  1685. }
  1686. else if (as.m_aligned.Empty())
  1687. {
  1688. /* check if the first one is actually on a blank line and then
  1689. * indent it. Eg:
  1690. *
  1691. * cout
  1692. * << "something";
  1693. */
  1694. chunk_t *prev = chunk_get_prev(pc);
  1695. if (prev && chunk_is_newline(prev))
  1696. {
  1697. indent_to_column(pc, pc->column_indent + cpd.settings[UO_indent_columns].u);
  1698. pc->column_indent = pc->column;
  1699. pc->flags |= PCF_DONT_INDENT;
  1700. }
  1701. /* first one can be anywhere */
  1702. as.Add(pc);
  1703. start = pc;
  1704. }
  1705. else if (chunk_is_newline(chunk_get_prev(pc)))
  1706. {
  1707. /* subsequent ones must be after a newline */
  1708. as.Add(pc);
  1709. }
  1710. }
  1711. else if (!as.m_aligned.Empty())
  1712. {
  1713. /* check if the given statement is on a line of its own, immediately following <<
  1714. * and then it. Eg:
  1715. *
  1716. * cout <<
  1717. * "something";
  1718. */
  1719. chunk_t *prev = chunk_get_prev(pc);
  1720. if (prev && chunk_is_newline(prev))
  1721. {
  1722. indent_to_column(pc, pc->column_indent + cpd.settings[UO_indent_columns].u);
  1723. pc->column_indent = pc->column;
  1724. pc->flags |= PCF_DONT_INDENT;
  1725. }
  1726. }
  1727. pc = chunk_get_next(pc);
  1728. }
  1729. as.End();
  1730. } // align_left_shift
  1731. static void align_oc_msg_colon(chunk_t *so)
  1732. {
  1733. LOG_FUNC_ENTRY();
  1734. AlignStack nas; /* for the parameter tag */
  1735. nas.Reset();
  1736. nas.m_right_align = !cpd.settings[UO_align_on_tabstop].b;
  1737. AlignStack cas; /* for the colons */
  1738. size_t span = cpd.settings[UO_align_oc_msg_colon_span].u;
  1739. cas.Start(span);
  1740. size_t level = so->level;
  1741. chunk_t *pc = chunk_get_next_ncnl(so, CNAV_PREPROC);
  1742. bool did_line = false;
  1743. bool has_colon = false;
  1744. size_t lcnt = 0; /* line count with no colon for span */
  1745. while ((pc != NULL) && (pc->level > level))
  1746. {
  1747. if (pc->level > (level + 1))
  1748. {
  1749. /* do nothing */
  1750. }
  1751. else if (chunk_is_newline(pc))
  1752. {
  1753. if (!has_colon)
  1754. {
  1755. ++lcnt;
  1756. }
  1757. did_line = false;
  1758. has_colon = !has_colon;
  1759. }
  1760. else if (!did_line && (lcnt < span + 1) && (pc->type == CT_OC_COLON))
  1761. {
  1762. has_colon = true;
  1763. cas.Add(pc);
  1764. chunk_t *tmp = chunk_get_prev(pc);
  1765. if ((tmp != NULL) &&
  1766. ((tmp->type == CT_OC_MSG_FUNC) ||
  1767. (tmp->type == CT_OC_MSG_NAME)))
  1768. {
  1769. nas.Add(tmp);
  1770. chunk_flags_set(tmp, PCF_DONT_INDENT);
  1771. }
  1772. did_line = true;
  1773. }
  1774. pc = chunk_get_next(pc, CNAV_PREPROC);
  1775. }
  1776. nas.m_skip_first = !cpd.settings[UO_align_oc_msg_colon_first].b;
  1777. cas.m_skip_first = !cpd.settings[UO_align_oc_msg_colon_first].b;
  1778. /* find the longest args that isn't the first one */
  1779. size_t first_len = 0;
  1780. size_t mlen = 0;
  1781. chunk_t *longest = NULL;
  1782. size_t len = nas.m_aligned.Len();
  1783. for (size_t idx = 0; idx < len; idx++)
  1784. {
  1785. chunk_t *tmp = nas.m_aligned.GetChunk(idx);
  1786. size_t tlen = tmp->str.size();
  1787. if (tlen > mlen)
  1788. {
  1789. mlen = tlen;
  1790. if (idx != 0)
  1791. {
  1792. longest = tmp;
  1793. }
  1794. }
  1795. if (idx == 0)
  1796. {
  1797. first_len = tlen + 1;
  1798. }
  1799. }
  1800. /* add spaces before the longest arg */
  1801. len = cpd.settings[UO_indent_oc_msg_colon].u;
  1802. size_t len_diff = mlen - first_len;
  1803. size_t indent_size = cpd.settings[UO_indent_columns].u;
  1804. /* Align with first colon if possible by removing spaces */
  1805. if (longest &&
  1806. cpd.settings[UO_indent_oc_msg_prioritize_first_colon].b &&
  1807. (len_diff > 0) &&
  1808. ((longest->column - len_diff) > (longest->brace_level * indent_size)))
  1809. {
  1810. longest->column -= len_diff;
  1811. }
  1812. else if (longest && (len > 0))
  1813. {
  1814. chunk_t chunk;
  1815. chunk.type = CT_SPACE;
  1816. chunk.orig_line = longest->orig_line;
  1817. chunk.parent_type = CT_NONE;
  1818. chunk.level = longest->level;
  1819. chunk.brace_level = longest->brace_level;
  1820. chunk.flags = longest->flags & PCF_COPY_FLAGS;
  1821. /* start at one since we already indent for the '[' */
  1822. for (size_t idx = 1; idx < len; idx++)
  1823. {
  1824. chunk.str.append(' ');
  1825. }
  1826. chunk_add_before(&chunk, longest);
  1827. }
  1828. nas.End();
  1829. cas.End();
  1830. } // align_oc_msg_colon
  1831. static void align_oc_msg_colons(void)
  1832. {
  1833. LOG_FUNC_ENTRY();
  1834. for (chunk_t *pc = chunk_get_head(); pc != NULL; pc = chunk_get_next(pc))
  1835. {
  1836. if ((pc->type == CT_SQUARE_OPEN) && (pc->parent_type == CT_OC_MSG))
  1837. {
  1838. align_oc_msg_colon(pc);
  1839. }
  1840. }
  1841. }
  1842. static void align_oc_decl_colon(void)
  1843. {
  1844. LOG_FUNC_ENTRY();
  1845. bool did_line;
  1846. AlignStack cas; /* for the colons */
  1847. AlignStack nas; /* for the parameter label */
  1848. cas.Start(4);
  1849. nas.Start(4);
  1850. nas.m_right_align = !cpd.settings[UO_align_on_tabstop].b;
  1851. chunk_t *pc = chunk_get_head();
  1852. while (pc != NULL)
  1853. {
  1854. if (pc->type != CT_OC_SCOPE)
  1855. {
  1856. pc = chunk_get_next(pc);
  1857. continue;
  1858. }
  1859. nas.Reset();
  1860. cas.Reset();
  1861. size_t level = pc->level;
  1862. pc = chunk_get_next_ncnl(pc, CNAV_PREPROC);
  1863. did_line = false;
  1864. while ((pc != NULL) && (pc->level >= level))
  1865. {
  1866. /* The decl ends with an open brace or semicolon */
  1867. if ((pc->type == CT_BRACE_OPEN) || chunk_is_semicolon(pc))
  1868. {
  1869. break;
  1870. }
  1871. if (chunk_is_newline(pc))
  1872. {
  1873. nas.NewLines(pc->nl_count);
  1874. cas.NewLines(pc->nl_count);
  1875. did_line = false;
  1876. }
  1877. else if (!did_line && (pc->type == CT_OC_COLON))
  1878. {
  1879. cas.Add(pc);
  1880. chunk_t *tmp = chunk_get_prev(pc, CNAV_PREPROC);
  1881. chunk_t *tmp2 = chunk_get_prev_ncnl(tmp, CNAV_PREPROC);
  1882. /* Check for an un-labeled parameter */
  1883. if ((tmp != NULL) &&
  1884. (tmp2 != NULL)
  1885. &&
  1886. ((tmp->type == CT_WORD) ||
  1887. (tmp->type == CT_TYPE) ||
  1888. (tmp->type == CT_OC_MSG_DECL) ||
  1889. (tmp->type == CT_OC_MSG_SPEC))
  1890. &&
  1891. ((tmp2->type == CT_WORD) ||
  1892. (tmp2->type == CT_TYPE) ||
  1893. (tmp2->type == CT_PAREN_CLOSE)))
  1894. {
  1895. nas.Add(tmp);
  1896. }
  1897. did_line = true;
  1898. }
  1899. pc = chunk_get_next(pc, CNAV_PREPROC);
  1900. }
  1901. nas.End();
  1902. cas.End();
  1903. }
  1904. } // align_oc_decl_colon
  1905. static void align_asm_colon(void)
  1906. {
  1907. LOG_FUNC_ENTRY();
  1908. bool did_nl;
  1909. AlignStack cas; /* for the colons */
  1910. cas.Start(4);
  1911. chunk_t *pc = chunk_get_head();
  1912. while (pc != NULL)
  1913. {
  1914. if (pc->type != CT_ASM_COLON)
  1915. {
  1916. pc = chunk_get_next(pc);
  1917. continue;
  1918. }
  1919. cas.Reset();
  1920. pc = chunk_get_next_ncnl(pc, CNAV_PREPROC);
  1921. size_t level = pc ? pc->level : 0;
  1922. did_nl = true;
  1923. while (pc && (pc->level >= level))
  1924. {
  1925. if (chunk_is_newline(pc))
  1926. {
  1927. cas.NewLines(pc->nl_count);
  1928. did_nl = true;
  1929. }
  1930. else if (pc->type == CT_ASM_COLON)
  1931. {
  1932. cas.Flush();
  1933. did_nl = true;
  1934. }
  1935. else if (did_nl)
  1936. {
  1937. did_nl = false;
  1938. cas.Add(pc);
  1939. }
  1940. pc = chunk_get_next_nc(pc, CNAV_PREPROC);
  1941. }
  1942. cas.End();
  1943. }
  1944. } // align_asm_colon