ASBeautifier.cpp 105 KB

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