@appthreat/atom 1.7.5 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) hide show
  1. package/astgen.js +6 -2
  2. package/index.js +3 -1
  3. package/package.json +3 -2
  4. package/phpastgen.js +31 -0
  5. package/plugins/autoload.php +25 -0
  6. package/plugins/bin/atom +1 -1
  7. package/plugins/bin/atom.bat +1 -1
  8. package/plugins/bin/php-parse +119 -0
  9. package/plugins/composer/ClassLoader.php +579 -0
  10. package/plugins/composer/InstalledVersions.php +359 -0
  11. package/plugins/composer/LICENSE +21 -0
  12. package/plugins/composer/autoload_classmap.php +260 -0
  13. package/plugins/composer/autoload_namespaces.php +9 -0
  14. package/plugins/composer/autoload_psr4.php +10 -0
  15. package/plugins/composer/autoload_real.php +36 -0
  16. package/plugins/composer/autoload_static.php +286 -0
  17. package/plugins/composer/installed.json +67 -0
  18. package/plugins/composer/installed.php +32 -0
  19. package/plugins/lib/{com.fasterxml.jackson.core.jackson-annotations-2.15.2.jar → com.fasterxml.jackson.core.jackson-annotations-2.16.0.jar} +0 -0
  20. package/plugins/lib/com.fasterxml.jackson.core.jackson-core-2.16.0.jar +0 -0
  21. package/plugins/lib/{com.fasterxml.jackson.core.jackson-databind-2.15.2.jar → com.fasterxml.jackson.core.jackson-databind-2.16.0.jar} +0 -0
  22. package/plugins/lib/{com.github.javaparser.javaparser-core-3.25.6.jar → com.github.javaparser.javaparser-core-3.25.7.jar} +0 -0
  23. package/plugins/lib/{com.github.javaparser.javaparser-symbol-solver-core-3.25.6.jar → com.github.javaparser.javaparser-symbol-solver-core-3.25.7.jar} +0 -0
  24. package/plugins/lib/{com.typesafe.config-1.4.2.jar → com.typesafe.config-1.4.3.jar} +0 -0
  25. package/plugins/lib/io.appthreat.atom-1.8.1-classpath.jar +0 -0
  26. package/plugins/lib/{io.appthreat.atom-1.7.5.jar → io.appthreat.atom-1.8.1.jar} +0 -0
  27. package/plugins/lib/{io.appthreat.c2cpg_3-1.0.10.jar → io.appthreat.c2cpg_3-1.1.3.jar} +0 -0
  28. package/plugins/lib/{io.appthreat.dataflowengineoss_3-1.0.10.jar → io.appthreat.dataflowengineoss_3-1.1.3.jar} +0 -0
  29. package/plugins/lib/{io.appthreat.javasrc2cpg_3-1.0.10.jar → io.appthreat.javasrc2cpg_3-1.1.3.jar} +0 -0
  30. package/plugins/lib/{io.appthreat.jimple2cpg_3-1.0.10.jar → io.appthreat.jimple2cpg_3-1.1.3.jar} +0 -0
  31. package/plugins/lib/{io.appthreat.jssrc2cpg_3-1.0.10.jar → io.appthreat.jssrc2cpg_3-1.1.3.jar} +0 -0
  32. package/plugins/lib/io.appthreat.php2atom_3-1.1.3.jar +0 -0
  33. package/plugins/lib/{io.appthreat.pysrc2cpg_3-1.0.10.jar → io.appthreat.pysrc2cpg_3-1.1.3.jar} +0 -0
  34. package/plugins/lib/{io.appthreat.semanticcpg_3-1.0.10.jar → io.appthreat.semanticcpg_3-1.1.3.jar} +0 -0
  35. package/plugins/lib/{io.appthreat.x2cpg_3-1.0.10.jar → io.appthreat.x2cpg_3-1.1.3.jar} +0 -0
  36. package/plugins/lib/io.circe.circe-core_3-0.14.6.jar +0 -0
  37. package/plugins/lib/io.circe.circe-generic_3-0.14.6.jar +0 -0
  38. package/plugins/lib/io.circe.circe-jawn_3-0.14.6.jar +0 -0
  39. package/plugins/lib/io.circe.circe-numbers_3-0.14.6.jar +0 -0
  40. package/plugins/lib/io.circe.circe-parser_3-0.14.6.jar +0 -0
  41. package/plugins/lib/org.gradle.gradle-tooling-api-8.5.jar +0 -0
  42. package/plugins/lib/{org.json4s.json4s-ast_3-4.0.6.jar → org.json4s.json4s-ast_3-4.0.7.jar} +0 -0
  43. package/plugins/lib/{org.json4s.json4s-core_3-4.0.6.jar → org.json4s.json4s-core_3-4.0.7.jar} +0 -0
  44. package/plugins/lib/{org.json4s.json4s-native-core_3-4.0.6.jar → org.json4s.json4s-native-core_3-4.0.7.jar} +0 -0
  45. package/plugins/lib/{org.json4s.json4s-native_3-4.0.6.jar → org.json4s.json4s-native_3-4.0.7.jar} +0 -0
  46. package/plugins/lib/{org.json4s.json4s-scalap_3-4.0.6.jar → org.json4s.json4s-scalap_3-4.0.7.jar} +0 -0
  47. package/plugins/lib/org.scala-lang.modules.scala-parser-combinators_3-2.3.0.jar +0 -0
  48. package/plugins/nikic/php-parser/.php-cs-fixer.dist.php +31 -0
  49. package/plugins/nikic/php-parser/LICENSE +29 -0
  50. package/plugins/nikic/php-parser/Makefile +10 -0
  51. package/plugins/nikic/php-parser/README.md +233 -0
  52. package/plugins/nikic/php-parser/bin/php-parse +206 -0
  53. package/plugins/nikic/php-parser/composer.json +43 -0
  54. package/plugins/nikic/php-parser/lib/PhpParser/Builder/ClassConst.php +150 -0
  55. package/plugins/nikic/php-parser/lib/PhpParser/Builder/Class_.php +151 -0
  56. package/plugins/nikic/php-parser/lib/PhpParser/Builder/Declaration.php +50 -0
  57. package/plugins/nikic/php-parser/lib/PhpParser/Builder/EnumCase.php +87 -0
  58. package/plugins/nikic/php-parser/lib/PhpParser/Builder/Enum_.php +116 -0
  59. package/plugins/nikic/php-parser/lib/PhpParser/Builder/FunctionLike.php +73 -0
  60. package/plugins/nikic/php-parser/lib/PhpParser/Builder/Function_.php +67 -0
  61. package/plugins/nikic/php-parser/lib/PhpParser/Builder/Interface_.php +94 -0
  62. package/plugins/nikic/php-parser/lib/PhpParser/Builder/Method.php +147 -0
  63. package/plugins/nikic/php-parser/lib/PhpParser/Builder/Namespace_.php +45 -0
  64. package/plugins/nikic/php-parser/lib/PhpParser/Builder/Param.php +149 -0
  65. package/plugins/nikic/php-parser/lib/PhpParser/Builder/Property.php +161 -0
  66. package/plugins/nikic/php-parser/lib/PhpParser/Builder/TraitUse.php +65 -0
  67. package/plugins/nikic/php-parser/lib/PhpParser/Builder/TraitUseAdaptation.php +145 -0
  68. package/plugins/nikic/php-parser/lib/PhpParser/Builder/Trait_.php +83 -0
  69. package/plugins/nikic/php-parser/lib/PhpParser/Builder/Use_.php +49 -0
  70. package/plugins/nikic/php-parser/lib/PhpParser/Builder.php +12 -0
  71. package/plugins/nikic/php-parser/lib/PhpParser/BuilderFactory.php +375 -0
  72. package/plugins/nikic/php-parser/lib/PhpParser/BuilderHelpers.php +333 -0
  73. package/plugins/nikic/php-parser/lib/PhpParser/Comment/Doc.php +6 -0
  74. package/plugins/nikic/php-parser/lib/PhpParser/Comment.php +207 -0
  75. package/plugins/nikic/php-parser/lib/PhpParser/ConstExprEvaluationException.php +6 -0
  76. package/plugins/nikic/php-parser/lib/PhpParser/ConstExprEvaluator.php +234 -0
  77. package/plugins/nikic/php-parser/lib/PhpParser/Error.php +171 -0
  78. package/plugins/nikic/php-parser/lib/PhpParser/ErrorHandler/Collecting.php +43 -0
  79. package/plugins/nikic/php-parser/lib/PhpParser/ErrorHandler/Throwing.php +17 -0
  80. package/plugins/nikic/php-parser/lib/PhpParser/ErrorHandler.php +12 -0
  81. package/plugins/nikic/php-parser/lib/PhpParser/Internal/DiffElem.php +31 -0
  82. package/plugins/nikic/php-parser/lib/PhpParser/Internal/Differ.php +178 -0
  83. package/plugins/nikic/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.php +71 -0
  84. package/plugins/nikic/php-parser/lib/PhpParser/Internal/TokenPolyfill.php +237 -0
  85. package/plugins/nikic/php-parser/lib/PhpParser/Internal/TokenStream.php +271 -0
  86. package/plugins/nikic/php-parser/lib/PhpParser/JsonDecoder.php +108 -0
  87. package/plugins/nikic/php-parser/lib/PhpParser/Lexer/Emulative.php +226 -0
  88. package/plugins/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php +49 -0
  89. package/plugins/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/EnumTokenEmulator.php +26 -0
  90. package/plugins/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ExplicitOctalEmulator.php +45 -0
  91. package/plugins/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/KeywordEmulator.php +56 -0
  92. package/plugins/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.php +19 -0
  93. package/plugins/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NullsafeTokenEmulator.php +60 -0
  94. package/plugins/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyFunctionTokenEmulator.php +31 -0
  95. package/plugins/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyTokenEmulator.php +31 -0
  96. package/plugins/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReverseEmulator.php +37 -0
  97. package/plugins/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/TokenEmulator.php +30 -0
  98. package/plugins/nikic/php-parser/lib/PhpParser/Lexer.php +116 -0
  99. package/plugins/nikic/php-parser/lib/PhpParser/Modifiers.php +69 -0
  100. package/plugins/nikic/php-parser/lib/PhpParser/NameContext.php +284 -0
  101. package/plugins/nikic/php-parser/lib/PhpParser/Node/Arg.php +44 -0
  102. package/plugins/nikic/php-parser/lib/PhpParser/Node/ArrayItem.php +43 -0
  103. package/plugins/nikic/php-parser/lib/PhpParser/Node/Attribute.php +33 -0
  104. package/plugins/nikic/php-parser/lib/PhpParser/Node/AttributeGroup.php +27 -0
  105. package/plugins/nikic/php-parser/lib/PhpParser/Node/ClosureUse.php +36 -0
  106. package/plugins/nikic/php-parser/lib/PhpParser/Node/ComplexType.php +13 -0
  107. package/plugins/nikic/php-parser/lib/PhpParser/Node/Const_.php +36 -0
  108. package/plugins/nikic/php-parser/lib/PhpParser/Node/DeclareItem.php +37 -0
  109. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayDimFetch.php +33 -0
  110. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayItem.php +3 -0
  111. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Array_.php +34 -0
  112. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/ArrowFunction.php +84 -0
  113. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Assign.php +33 -0
  114. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php +11 -0
  115. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php +11 -0
  116. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php +11 -0
  117. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Coalesce.php +11 -0
  118. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Concat.php +11 -0
  119. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Div.php +11 -0
  120. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Minus.php +11 -0
  121. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Mod.php +11 -0
  122. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Mul.php +11 -0
  123. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Plus.php +11 -0
  124. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Pow.php +11 -0
  125. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php +11 -0
  126. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php +11 -0
  127. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp.php +29 -0
  128. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/AssignRef.php +33 -0
  129. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php +15 -0
  130. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php +15 -0
  131. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php +15 -0
  132. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php +15 -0
  133. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php +15 -0
  134. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php +15 -0
  135. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Concat.php +15 -0
  136. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Div.php +15 -0
  137. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Equal.php +15 -0
  138. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Greater.php +15 -0
  139. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php +15 -0
  140. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Identical.php +15 -0
  141. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php +15 -0
  142. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php +15 -0
  143. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php +15 -0
  144. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Minus.php +15 -0
  145. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Mod.php +15 -0
  146. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Mul.php +15 -0
  147. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php +15 -0
  148. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php +15 -0
  149. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Plus.php +15 -0
  150. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Pow.php +15 -0
  151. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php +15 -0
  152. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php +15 -0
  153. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Smaller.php +15 -0
  154. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php +15 -0
  155. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php +15 -0
  156. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp.php +37 -0
  157. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BitwiseNot.php +29 -0
  158. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/BooleanNot.php +29 -0
  159. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/CallLike.php +35 -0
  160. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Array_.php +11 -0
  161. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Bool_.php +11 -0
  162. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Double.php +16 -0
  163. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Int_.php +11 -0
  164. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Object_.php +11 -0
  165. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/String_.php +11 -0
  166. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Unset_.php +11 -0
  167. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Cast.php +25 -0
  168. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/ClassConstFetch.php +36 -0
  169. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Clone_.php +29 -0
  170. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Closure.php +86 -0
  171. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/ClosureUse.php +3 -0
  172. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/ConstFetch.php +30 -0
  173. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Empty_.php +29 -0
  174. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Error.php +30 -0
  175. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/ErrorSuppress.php +29 -0
  176. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Eval_.php +29 -0
  177. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Exit_.php +33 -0
  178. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/FuncCall.php +38 -0
  179. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Include_.php +38 -0
  180. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Instanceof_.php +35 -0
  181. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Isset_.php +29 -0
  182. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/List_.php +34 -0
  183. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Match_.php +32 -0
  184. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/MethodCall.php +45 -0
  185. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/New_.php +40 -0
  186. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafeMethodCall.php +45 -0
  187. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafePropertyFetch.php +35 -0
  188. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/PostDec.php +29 -0
  189. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/PostInc.php +29 -0
  190. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/PreDec.php +29 -0
  191. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/PreInc.php +29 -0
  192. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Print_.php +29 -0
  193. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/PropertyFetch.php +35 -0
  194. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/ShellExec.php +30 -0
  195. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/StaticCall.php +45 -0
  196. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/StaticPropertyFetch.php +36 -0
  197. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Ternary.php +37 -0
  198. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Throw_.php +29 -0
  199. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryMinus.php +29 -0
  200. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryPlus.php +29 -0
  201. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Variable.php +29 -0
  202. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/YieldFrom.php +29 -0
  203. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr/Yield_.php +33 -0
  204. package/plugins/nikic/php-parser/lib/PhpParser/Node/Expr.php +8 -0
  205. package/plugins/nikic/php-parser/lib/PhpParser/Node/FunctionLike.php +40 -0
  206. package/plugins/nikic/php-parser/lib/PhpParser/Node/Identifier.php +75 -0
  207. package/plugins/nikic/php-parser/lib/PhpParser/Node/InterpolatedStringPart.php +32 -0
  208. package/plugins/nikic/php-parser/lib/PhpParser/Node/IntersectionType.php +27 -0
  209. package/plugins/nikic/php-parser/lib/PhpParser/Node/MatchArm.php +30 -0
  210. package/plugins/nikic/php-parser/lib/PhpParser/Node/Name/FullyQualified.php +49 -0
  211. package/plugins/nikic/php-parser/lib/PhpParser/Node/Name/Relative.php +49 -0
  212. package/plugins/nikic/php-parser/lib/PhpParser/Node/Name.php +269 -0
  213. package/plugins/nikic/php-parser/lib/PhpParser/Node/NullableType.php +29 -0
  214. package/plugins/nikic/php-parser/lib/PhpParser/Node/Param.php +84 -0
  215. package/plugins/nikic/php-parser/lib/PhpParser/Node/PropertyItem.php +37 -0
  216. package/plugins/nikic/php-parser/lib/PhpParser/Node/Scalar/DNumber.php +3 -0
  217. package/plugins/nikic/php-parser/lib/PhpParser/Node/Scalar/Encapsed.php +3 -0
  218. package/plugins/nikic/php-parser/lib/PhpParser/Node/Scalar/EncapsedStringPart.php +3 -0
  219. package/plugins/nikic/php-parser/lib/PhpParser/Node/Scalar/Float_.php +78 -0
  220. package/plugins/nikic/php-parser/lib/PhpParser/Node/Scalar/Int_.php +82 -0
  221. package/plugins/nikic/php-parser/lib/PhpParser/Node/Scalar/InterpolatedString.php +34 -0
  222. package/plugins/nikic/php-parser/lib/PhpParser/Node/Scalar/LNumber.php +3 -0
  223. package/plugins/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Class_.php +15 -0
  224. package/plugins/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Dir.php +15 -0
  225. package/plugins/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/File.php +15 -0
  226. package/plugins/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Function_.php +15 -0
  227. package/plugins/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Line.php +15 -0
  228. package/plugins/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Method.php +15 -0
  229. package/plugins/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php +15 -0
  230. package/plugins/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Trait_.php +15 -0
  231. package/plugins/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst.php +27 -0
  232. package/plugins/nikic/php-parser/lib/PhpParser/Node/Scalar/String_.php +161 -0
  233. package/plugins/nikic/php-parser/lib/PhpParser/Node/Scalar.php +6 -0
  234. package/plugins/nikic/php-parser/lib/PhpParser/Node/StaticVar.php +39 -0
  235. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Block.php +29 -0
  236. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Break_.php +29 -0
  237. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Case_.php +33 -0
  238. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Catch_.php +40 -0
  239. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassConst.php +77 -0
  240. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassLike.php +109 -0
  241. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassMethod.php +154 -0
  242. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Class_.php +94 -0
  243. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Const_.php +29 -0
  244. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Continue_.php +29 -0
  245. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/DeclareDeclare.php +3 -0
  246. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Declare_.php +34 -0
  247. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Do_.php +33 -0
  248. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Echo_.php +29 -0
  249. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/ElseIf_.php +33 -0
  250. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Else_.php +29 -0
  251. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/EnumCase.php +36 -0
  252. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Enum_.php +44 -0
  253. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Expression.php +32 -0
  254. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Finally_.php +29 -0
  255. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/For_.php +47 -0
  256. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Foreach_.php +50 -0
  257. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Function_.php +81 -0
  258. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Global_.php +29 -0
  259. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Goto_.php +30 -0
  260. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/GroupUse.php +41 -0
  261. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/HaltCompiler.php +29 -0
  262. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/If_.php +46 -0
  263. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/InlineHTML.php +29 -0
  264. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Interface_.php +40 -0
  265. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Label.php +30 -0
  266. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Namespace_.php +37 -0
  267. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Nop.php +16 -0
  268. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Property.php +82 -0
  269. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/PropertyProperty.php +3 -0
  270. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Return_.php +29 -0
  271. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/StaticVar.php +3 -0
  272. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Static_.php +30 -0
  273. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Switch_.php +33 -0
  274. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUse.php +33 -0
  275. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php +37 -0
  276. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php +33 -0
  277. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation.php +12 -0
  278. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Trait_.php +34 -0
  279. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/TryCatch.php +37 -0
  280. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Unset_.php +29 -0
  281. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/UseUse.php +3 -0
  282. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/Use_.php +47 -0
  283. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt/While_.php +33 -0
  284. package/plugins/nikic/php-parser/lib/PhpParser/Node/Stmt.php +8 -0
  285. package/plugins/nikic/php-parser/lib/PhpParser/Node/UnionType.php +27 -0
  286. package/plugins/nikic/php-parser/lib/PhpParser/Node/UseItem.php +55 -0
  287. package/plugins/nikic/php-parser/lib/PhpParser/Node/VarLikeIdentifier.php +16 -0
  288. package/plugins/nikic/php-parser/lib/PhpParser/Node/VariadicPlaceholder.php +27 -0
  289. package/plugins/nikic/php-parser/lib/PhpParser/Node.php +146 -0
  290. package/plugins/nikic/php-parser/lib/PhpParser/NodeAbstract.php +178 -0
  291. package/plugins/nikic/php-parser/lib/PhpParser/NodeDumper.php +290 -0
  292. package/plugins/nikic/php-parser/lib/PhpParser/NodeFinder.php +90 -0
  293. package/plugins/nikic/php-parser/lib/PhpParser/NodeTraverser.php +278 -0
  294. package/plugins/nikic/php-parser/lib/PhpParser/NodeTraverserInterface.php +26 -0
  295. package/plugins/nikic/php-parser/lib/PhpParser/NodeVisitor/CloningVisitor.php +19 -0
  296. package/plugins/nikic/php-parser/lib/PhpParser/NodeVisitor/CommentAnnotatingVisitor.php +82 -0
  297. package/plugins/nikic/php-parser/lib/PhpParser/NodeVisitor/FindingVisitor.php +47 -0
  298. package/plugins/nikic/php-parser/lib/PhpParser/NodeVisitor/FirstFindingVisitor.php +49 -0
  299. package/plugins/nikic/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php +262 -0
  300. package/plugins/nikic/php-parser/lib/PhpParser/NodeVisitor/NodeConnectingVisitor.php +51 -0
  301. package/plugins/nikic/php-parser/lib/PhpParser/NodeVisitor/ParentConnectingVisitor.php +38 -0
  302. package/plugins/nikic/php-parser/lib/PhpParser/NodeVisitor.php +124 -0
  303. package/plugins/nikic/php-parser/lib/PhpParser/NodeVisitorAbstract.php +24 -0
  304. package/plugins/nikic/php-parser/lib/PhpParser/Parser/Php7.php +2699 -0
  305. package/plugins/nikic/php-parser/lib/PhpParser/Parser/Php8.php +2717 -0
  306. package/plugins/nikic/php-parser/lib/PhpParser/Parser.php +24 -0
  307. package/plugins/nikic/php-parser/lib/PhpParser/ParserAbstract.php +1241 -0
  308. package/plugins/nikic/php-parser/lib/PhpParser/ParserFactory.php +42 -0
  309. package/plugins/nikic/php-parser/lib/PhpParser/PhpVersion.php +164 -0
  310. package/plugins/nikic/php-parser/lib/PhpParser/PrettyPrinter/Standard.php +1177 -0
  311. package/plugins/nikic/php-parser/lib/PhpParser/PrettyPrinter.php +51 -0
  312. package/plugins/nikic/php-parser/lib/PhpParser/PrettyPrinterAbstract.php +1655 -0
  313. package/plugins/nikic/php-parser/lib/PhpParser/Token.php +18 -0
  314. package/plugins/nikic/php-parser/lib/PhpParser/compatibility_tokens.php +56 -0
  315. package/plugins/nikic/php-parser/phpstan-baseline.neon +236 -0
  316. package/plugins/nikic/php-parser/phpstan.neon.dist +8 -0
  317. package/utils.mjs +10 -0
  318. package/plugins/lib/com.fasterxml.jackson.core.jackson-core-2.15.2.jar +0 -0
  319. package/plugins/lib/io.appthreat.atom-1.7.5-classpath.jar +0 -0
  320. package/plugins/lib/io.circe.circe-core_3-0.14.5.jar +0 -0
  321. package/plugins/lib/io.circe.circe-generic_3-0.14.5.jar +0 -0
  322. package/plugins/lib/io.circe.circe-jawn_3-0.14.5.jar +0 -0
  323. package/plugins/lib/io.circe.circe-numbers_3-0.14.5.jar +0 -0
  324. package/plugins/lib/io.circe.circe-parser_3-0.14.5.jar +0 -0
  325. package/plugins/lib/org.gradle.gradle-tooling-api-8.3.jar +0 -0
  326. package/plugins/lib/org.scala-lang.modules.scala-parser-combinators_3-2.2.0.jar +0 -0
@@ -0,0 +1,1655 @@
1
+ <?php declare(strict_types=1);
2
+
3
+ namespace PhpParser;
4
+
5
+ use PhpParser\Internal\DiffElem;
6
+ use PhpParser\Internal\Differ;
7
+ use PhpParser\Internal\PrintableNewAnonClassNode;
8
+ use PhpParser\Internal\TokenStream;
9
+ use PhpParser\Node\AttributeGroup;
10
+ use PhpParser\Node\Expr;
11
+ use PhpParser\Node\Expr\AssignOp;
12
+ use PhpParser\Node\Expr\BinaryOp;
13
+ use PhpParser\Node\Expr\Cast;
14
+ use PhpParser\Node\IntersectionType;
15
+ use PhpParser\Node\MatchArm;
16
+ use PhpParser\Node\Param;
17
+ use PhpParser\Node\Scalar;
18
+ use PhpParser\Node\Stmt;
19
+ use PhpParser\Node\UnionType;
20
+
21
+ abstract class PrettyPrinterAbstract implements PrettyPrinter {
22
+ protected const FIXUP_PREC_LEFT = 0; // LHS operand affected by precedence
23
+ protected const FIXUP_PREC_RIGHT = 1; // RHS operand affected by precedence
24
+ protected const FIXUP_PREC_UNARY = 2; // Only operand affected by precedence
25
+ protected const FIXUP_CALL_LHS = 3; // LHS of call
26
+ protected const FIXUP_DEREF_LHS = 4; // LHS of dereferencing operation
27
+ protected const FIXUP_STATIC_DEREF_LHS = 5; // LHS of static dereferencing operation
28
+ protected const FIXUP_BRACED_NAME = 6; // Name operand that may require bracing
29
+ protected const FIXUP_VAR_BRACED_NAME = 7; // Name operand that may require ${} bracing
30
+ protected const FIXUP_ENCAPSED = 8; // Encapsed string part
31
+ protected const FIXUP_NEW = 9; // New/instanceof operand
32
+
33
+ protected const MAX_PRECEDENCE = 1000;
34
+
35
+ /** @var array<class-string, array{int, int, int}> */
36
+ protected array $precedenceMap = [
37
+ // [precedence, precedenceLHS, precedenceRHS]
38
+ // Where the latter two are the precedences to use for the LHS and RHS of a binary operator,
39
+ // where 1 is added to one of the sides depending on associativity. This information is not
40
+ // used for unary operators and set to -1.
41
+ Expr\Clone_::class => [-10, 0, 1],
42
+ BinaryOp\Pow::class => [ 0, 0, 1],
43
+ Expr\BitwiseNot::class => [ 10, -1, -1],
44
+ Expr\UnaryPlus::class => [ 10, -1, -1],
45
+ Expr\UnaryMinus::class => [ 10, -1, -1],
46
+ Cast\Int_::class => [ 10, -1, -1],
47
+ Cast\Double::class => [ 10, -1, -1],
48
+ Cast\String_::class => [ 10, -1, -1],
49
+ Cast\Array_::class => [ 10, -1, -1],
50
+ Cast\Object_::class => [ 10, -1, -1],
51
+ Cast\Bool_::class => [ 10, -1, -1],
52
+ Cast\Unset_::class => [ 10, -1, -1],
53
+ Expr\ErrorSuppress::class => [ 10, -1, -1],
54
+ Expr\Instanceof_::class => [ 20, -1, -1],
55
+ Expr\BooleanNot::class => [ 30, -1, -1],
56
+ BinaryOp\Mul::class => [ 40, 41, 40],
57
+ BinaryOp\Div::class => [ 40, 41, 40],
58
+ BinaryOp\Mod::class => [ 40, 41, 40],
59
+ BinaryOp\Plus::class => [ 50, 51, 50],
60
+ BinaryOp\Minus::class => [ 50, 51, 50],
61
+ BinaryOp\Concat::class => [ 50, 51, 50],
62
+ BinaryOp\ShiftLeft::class => [ 60, 61, 60],
63
+ BinaryOp\ShiftRight::class => [ 60, 61, 60],
64
+ BinaryOp\Smaller::class => [ 70, 70, 70],
65
+ BinaryOp\SmallerOrEqual::class => [ 70, 70, 70],
66
+ BinaryOp\Greater::class => [ 70, 70, 70],
67
+ BinaryOp\GreaterOrEqual::class => [ 70, 70, 70],
68
+ BinaryOp\Equal::class => [ 80, 80, 80],
69
+ BinaryOp\NotEqual::class => [ 80, 80, 80],
70
+ BinaryOp\Identical::class => [ 80, 80, 80],
71
+ BinaryOp\NotIdentical::class => [ 80, 80, 80],
72
+ BinaryOp\Spaceship::class => [ 80, 80, 80],
73
+ BinaryOp\BitwiseAnd::class => [ 90, 91, 90],
74
+ BinaryOp\BitwiseXor::class => [100, 101, 100],
75
+ BinaryOp\BitwiseOr::class => [110, 111, 110],
76
+ BinaryOp\BooleanAnd::class => [120, 121, 120],
77
+ BinaryOp\BooleanOr::class => [130, 131, 130],
78
+ BinaryOp\Coalesce::class => [140, 140, 141],
79
+ Expr\Ternary::class => [150, -1, -1],
80
+ Expr\Assign::class => [160, -1, -1],
81
+ Expr\AssignRef::class => [160, -1, -1],
82
+ AssignOp\Plus::class => [160, -1, -1],
83
+ AssignOp\Minus::class => [160, -1, -1],
84
+ AssignOp\Mul::class => [160, -1, -1],
85
+ AssignOp\Div::class => [160, -1, -1],
86
+ AssignOp\Concat::class => [160, -1, -1],
87
+ AssignOp\Mod::class => [160, -1, -1],
88
+ AssignOp\BitwiseAnd::class => [160, -1, -1],
89
+ AssignOp\BitwiseOr::class => [160, -1, -1],
90
+ AssignOp\BitwiseXor::class => [160, -1, -1],
91
+ AssignOp\ShiftLeft::class => [160, -1, -1],
92
+ AssignOp\ShiftRight::class => [160, -1, -1],
93
+ AssignOp\Pow::class => [160, -1, -1],
94
+ AssignOp\Coalesce::class => [160, -1, -1],
95
+ Expr\YieldFrom::class => [170, -1, -1],
96
+ Expr\Yield_::class => [175, -1, -1],
97
+ Expr\Print_::class => [180, -1, -1],
98
+ BinaryOp\LogicalAnd::class => [190, 191, 190],
99
+ BinaryOp\LogicalXor::class => [200, 201, 200],
100
+ BinaryOp\LogicalOr::class => [210, 211, 210],
101
+ Expr\Include_::class => [220, -1, -1],
102
+ Expr\ArrowFunction::class => [230, -1, -1],
103
+ Expr\Throw_::class => [240, -1, -1],
104
+ ];
105
+
106
+ /** @var int Current indentation level. */
107
+ protected int $indentLevel;
108
+ /** @var string Newline style. Does not include current indentation. */
109
+ protected string $newline;
110
+ /** @var string Newline including current indentation. */
111
+ protected string $nl;
112
+ /** @var string|null Token placed at end of doc string to ensure it is followed by a newline.
113
+ * Null if flexible doc strings are used. */
114
+ protected ?string $docStringEndToken;
115
+ /** @var bool Whether semicolon namespaces can be used (i.e. no global namespace is used) */
116
+ protected bool $canUseSemicolonNamespaces;
117
+ /** @var bool Whether to use short array syntax if the node specifies no preference */
118
+ protected bool $shortArraySyntax;
119
+ /** @var PhpVersion PHP version to target */
120
+ protected PhpVersion $phpVersion;
121
+
122
+ /** @var TokenStream|null Original tokens for use in format-preserving pretty print */
123
+ protected ?TokenStream $origTokens;
124
+ /** @var Internal\Differ<Node> Differ for node lists */
125
+ protected Differ $nodeListDiffer;
126
+ /** @var array<string, bool> Map determining whether a certain character is a label character */
127
+ protected array $labelCharMap;
128
+ /**
129
+ * @var array<string, array<string, int>> Map from token classes and subnode names to FIXUP_* constants.
130
+ * This is used during format-preserving prints to place additional parens/braces if necessary.
131
+ */
132
+ protected array $fixupMap;
133
+ /**
134
+ * @var array<string, array{left?: int|string, right?: int|string}> Map from "{$node->getType()}->{$subNode}"
135
+ * to ['left' => $l, 'right' => $r], where $l and $r specify the token type that needs to be stripped
136
+ * when removing this node.
137
+ */
138
+ protected array $removalMap;
139
+ /**
140
+ * @var array<string, array{int|string|null, bool, string|null, string|null}> Map from
141
+ * "{$node->getType()}->{$subNode}" to [$find, $beforeToken, $extraLeft, $extraRight].
142
+ * $find is an optional token after which the insertion occurs. $extraLeft/Right
143
+ * are optionally added before/after the main insertions.
144
+ */
145
+ protected array $insertionMap;
146
+ /**
147
+ * @var array<string, string> Map From "{$class}->{$subNode}" to string that should be inserted
148
+ * between elements of this list subnode.
149
+ */
150
+ protected array $listInsertionMap;
151
+
152
+ /**
153
+ * @var array<string, array{int|string|null, string, string}>
154
+ */
155
+ protected array $emptyListInsertionMap;
156
+ /** @var array<string, array{string, int}> Map from "{$class}->{$subNode}" to [$printFn, $token]
157
+ * where $printFn is the function to print the modifiers and $token is the token before which
158
+ * the modifiers should be reprinted. */
159
+ protected array $modifierChangeMap;
160
+
161
+ /**
162
+ * Creates a pretty printer instance using the given options.
163
+ *
164
+ * Supported options:
165
+ * * PhpVersion $phpVersion: The PHP version to target (default to PHP 7.4). This option
166
+ * controls compatibility of the generated code with older PHP
167
+ * versions in cases where a simple stylistic choice exists (e.g.
168
+ * array() vs []). It is safe to pretty-print an AST for a newer
169
+ * PHP version while specifying an older target (but the result will
170
+ * of course not be compatible with the older version in that case).
171
+ * * string $newline: The newline style to use. Should be "\n" (default) or "\r\n".
172
+ * * bool $shortArraySyntax: Whether to use [] instead of array() as the default array
173
+ * syntax, if the node does not specify a format. Defaults to whether
174
+ * the phpVersion support short array syntax.
175
+ *
176
+ * @param array{
177
+ * phpVersion?: PhpVersion, newline?: string, shortArraySyntax?: bool
178
+ * } $options Dictionary of formatting options
179
+ */
180
+ public function __construct(array $options = []) {
181
+ $this->phpVersion = $options['phpVersion'] ?? PhpVersion::fromComponents(7, 4);
182
+
183
+ $this->newline = $options['newline'] ?? "\n";
184
+ if ($this->newline !== "\n" && $this->newline != "\r\n") {
185
+ throw new \LogicException('Option "newline" must be one of "\n" or "\r\n"');
186
+ }
187
+
188
+ $this->shortArraySyntax =
189
+ $options['shortArraySyntax'] ?? $this->phpVersion->supportsShortArraySyntax();
190
+ $this->docStringEndToken =
191
+ $this->phpVersion->supportsFlexibleHeredoc() ? null : '_DOC_STRING_END_' . mt_rand();
192
+ }
193
+
194
+ /**
195
+ * Reset pretty printing state.
196
+ */
197
+ protected function resetState(): void {
198
+ $this->indentLevel = 0;
199
+ $this->nl = $this->newline;
200
+ $this->origTokens = null;
201
+ }
202
+
203
+ /**
204
+ * Set indentation level
205
+ *
206
+ * @param int $level Level in number of spaces
207
+ */
208
+ protected function setIndentLevel(int $level): void {
209
+ $this->indentLevel = $level;
210
+ $this->nl = $this->newline . \str_repeat(' ', $level);
211
+ }
212
+
213
+ /**
214
+ * Increase indentation level.
215
+ */
216
+ protected function indent(): void {
217
+ $this->indentLevel += 4;
218
+ $this->nl .= ' ';
219
+ }
220
+
221
+ /**
222
+ * Decrease indentation level.
223
+ */
224
+ protected function outdent(): void {
225
+ assert($this->indentLevel >= 4);
226
+ $this->indentLevel -= 4;
227
+ $this->nl = $this->newline . str_repeat(' ', $this->indentLevel);
228
+ }
229
+
230
+ /**
231
+ * Pretty prints an array of statements.
232
+ *
233
+ * @param Node[] $stmts Array of statements
234
+ *
235
+ * @return string Pretty printed statements
236
+ */
237
+ public function prettyPrint(array $stmts): string {
238
+ $this->resetState();
239
+ $this->preprocessNodes($stmts);
240
+
241
+ return ltrim($this->handleMagicTokens($this->pStmts($stmts, false)));
242
+ }
243
+
244
+ /**
245
+ * Pretty prints an expression.
246
+ *
247
+ * @param Expr $node Expression node
248
+ *
249
+ * @return string Pretty printed node
250
+ */
251
+ public function prettyPrintExpr(Expr $node): string {
252
+ $this->resetState();
253
+ return $this->handleMagicTokens($this->p($node));
254
+ }
255
+
256
+ /**
257
+ * Pretty prints a file of statements (includes the opening <?php tag if it is required).
258
+ *
259
+ * @param Node[] $stmts Array of statements
260
+ *
261
+ * @return string Pretty printed statements
262
+ */
263
+ public function prettyPrintFile(array $stmts): string {
264
+ if (!$stmts) {
265
+ return "<?php" . $this->newline . $this->newline;
266
+ }
267
+
268
+ $p = "<?php" . $this->newline . $this->newline . $this->prettyPrint($stmts);
269
+
270
+ if ($stmts[0] instanceof Stmt\InlineHTML) {
271
+ $p = preg_replace('/^<\?php\s+\?>\r?\n?/', '', $p);
272
+ }
273
+ if ($stmts[count($stmts) - 1] instanceof Stmt\InlineHTML) {
274
+ $p = preg_replace('/<\?php$/', '', rtrim($p));
275
+ }
276
+
277
+ return $p;
278
+ }
279
+
280
+ /**
281
+ * Preprocesses the top-level nodes to initialize pretty printer state.
282
+ *
283
+ * @param Node[] $nodes Array of nodes
284
+ */
285
+ protected function preprocessNodes(array $nodes): void {
286
+ /* We can use semicolon-namespaces unless there is a global namespace declaration */
287
+ $this->canUseSemicolonNamespaces = true;
288
+ foreach ($nodes as $node) {
289
+ if ($node instanceof Stmt\Namespace_ && null === $node->name) {
290
+ $this->canUseSemicolonNamespaces = false;
291
+ break;
292
+ }
293
+ }
294
+ }
295
+
296
+ /**
297
+ * Handles (and removes) doc-string-end tokens.
298
+ */
299
+ protected function handleMagicTokens(string $str): string {
300
+ if ($this->docStringEndToken !== null) {
301
+ // Replace doc-string-end tokens with nothing or a newline
302
+ $str = str_replace(
303
+ $this->docStringEndToken . ';' . $this->newline,
304
+ ';' . $this->newline,
305
+ $str);
306
+ $str = str_replace($this->docStringEndToken, $this->newline, $str);
307
+ }
308
+
309
+ return $str;
310
+ }
311
+
312
+ /**
313
+ * Pretty prints an array of nodes (statements) and indents them optionally.
314
+ *
315
+ * @param Node[] $nodes Array of nodes
316
+ * @param bool $indent Whether to indent the printed nodes
317
+ *
318
+ * @return string Pretty printed statements
319
+ */
320
+ protected function pStmts(array $nodes, bool $indent = true): string {
321
+ if ($indent) {
322
+ $this->indent();
323
+ }
324
+
325
+ $result = '';
326
+ foreach ($nodes as $node) {
327
+ $comments = $node->getComments();
328
+ if ($comments) {
329
+ $result .= $this->nl . $this->pComments($comments);
330
+ if ($node instanceof Stmt\Nop) {
331
+ continue;
332
+ }
333
+ }
334
+
335
+ $result .= $this->nl . $this->p($node);
336
+ }
337
+
338
+ if ($indent) {
339
+ $this->outdent();
340
+ }
341
+
342
+ return $result;
343
+ }
344
+
345
+ /**
346
+ * Pretty-print an infix operation while taking precedence into account.
347
+ *
348
+ * @param string $class Node class of operator
349
+ * @param Node $leftNode Left-hand side node
350
+ * @param string $operatorString String representation of the operator
351
+ * @param Node $rightNode Right-hand side node
352
+ * @param int $precedence Precedence of parent operator
353
+ * @param int $lhsPrecedence Precedence for unary operator on LHS of binary operator
354
+ *
355
+ * @return string Pretty printed infix operation
356
+ */
357
+ protected function pInfixOp(
358
+ string $class, Node $leftNode, string $operatorString, Node $rightNode,
359
+ int $precedence, int $lhsPrecedence
360
+ ): string {
361
+ list($opPrecedence, $newPrecedenceLHS, $newPrecedenceRHS) = $this->precedenceMap[$class];
362
+ $prefix = '';
363
+ $suffix = '';
364
+ if ($opPrecedence >= $precedence) {
365
+ $prefix = '(';
366
+ $suffix = ')';
367
+ $lhsPrecedence = self::MAX_PRECEDENCE;
368
+ }
369
+ return $prefix . $this->p($leftNode, $newPrecedenceLHS, $newPrecedenceLHS)
370
+ . $operatorString . $this->p($rightNode, $newPrecedenceRHS, $lhsPrecedence) . $suffix;
371
+ }
372
+
373
+ /**
374
+ * Pretty-print a prefix operation while taking precedence into account.
375
+ *
376
+ * @param string $class Node class of operator
377
+ * @param string $operatorString String representation of the operator
378
+ * @param Node $node Node
379
+ * @param int $precedence Precedence of parent operator
380
+ * @param int $lhsPrecedence Precedence for unary operator on LHS of binary operator
381
+ *
382
+ * @return string Pretty printed prefix operation
383
+ */
384
+ protected function pPrefixOp(string $class, string $operatorString, Node $node, int $precedence, int $lhsPrecedence): string {
385
+ $opPrecedence = $this->precedenceMap[$class][0];
386
+ $prefix = '';
387
+ $suffix = '';
388
+ if ($opPrecedence >= $lhsPrecedence) {
389
+ $prefix = '(';
390
+ $suffix = ')';
391
+ $lhsPrecedence = self::MAX_PRECEDENCE;
392
+ }
393
+ $printedArg = $this->p($node, $opPrecedence, $lhsPrecedence);
394
+ if (($operatorString === '+' && $printedArg[0] === '+') ||
395
+ ($operatorString === '-' && $printedArg[0] === '-')
396
+ ) {
397
+ // Avoid printing +(+$a) as ++$a and similar.
398
+ $printedArg = '(' . $printedArg . ')';
399
+ }
400
+ return $prefix . $operatorString . $printedArg . $suffix;
401
+ }
402
+
403
+ /**
404
+ * Pretty-print a postfix operation while taking precedence into account.
405
+ *
406
+ * @param string $class Node class of operator
407
+ * @param string $operatorString String representation of the operator
408
+ * @param Node $node Node
409
+ * @param int $precedence Precedence of parent operator
410
+ * @param int $lhsPrecedence Precedence for unary operator on LHS of binary operator
411
+ *
412
+ * @return string Pretty printed postfix operation
413
+ */
414
+ protected function pPostfixOp(string $class, Node $node, string $operatorString, int $precedence, int $lhsPrecedence): string {
415
+ $opPrecedence = $this->precedenceMap[$class][0];
416
+ $prefix = '';
417
+ $suffix = '';
418
+ if ($opPrecedence >= $precedence) {
419
+ $prefix = '(';
420
+ $suffix = ')';
421
+ $lhsPrecedence = self::MAX_PRECEDENCE;
422
+ }
423
+ if ($opPrecedence < $lhsPrecedence) {
424
+ $lhsPrecedence = $opPrecedence;
425
+ }
426
+ return $prefix . $this->p($node, $opPrecedence, $lhsPrecedence) . $operatorString . $suffix;
427
+ }
428
+
429
+ /**
430
+ * Pretty prints an array of nodes and implodes the printed values.
431
+ *
432
+ * @param Node[] $nodes Array of Nodes to be printed
433
+ * @param string $glue Character to implode with
434
+ *
435
+ * @return string Imploded pretty printed nodes> $pre
436
+ */
437
+ protected function pImplode(array $nodes, string $glue = ''): string {
438
+ $pNodes = [];
439
+ foreach ($nodes as $node) {
440
+ if (null === $node) {
441
+ $pNodes[] = '';
442
+ } else {
443
+ $pNodes[] = $this->p($node);
444
+ }
445
+ }
446
+
447
+ return implode($glue, $pNodes);
448
+ }
449
+
450
+ /**
451
+ * Pretty prints an array of nodes and implodes the printed values with commas.
452
+ *
453
+ * @param Node[] $nodes Array of Nodes to be printed
454
+ *
455
+ * @return string Comma separated pretty printed nodes
456
+ */
457
+ protected function pCommaSeparated(array $nodes): string {
458
+ return $this->pImplode($nodes, ', ');
459
+ }
460
+
461
+ /**
462
+ * Pretty prints a comma-separated list of nodes in multiline style, including comments.
463
+ *
464
+ * The result includes a leading newline and one level of indentation (same as pStmts).
465
+ *
466
+ * @param Node[] $nodes Array of Nodes to be printed
467
+ * @param bool $trailingComma Whether to use a trailing comma
468
+ *
469
+ * @return string Comma separated pretty printed nodes in multiline style
470
+ */
471
+ protected function pCommaSeparatedMultiline(array $nodes, bool $trailingComma): string {
472
+ $this->indent();
473
+
474
+ $result = '';
475
+ $lastIdx = count($nodes) - 1;
476
+ foreach ($nodes as $idx => $node) {
477
+ if ($node !== null) {
478
+ $comments = $node->getComments();
479
+ if ($comments) {
480
+ $result .= $this->nl . $this->pComments($comments);
481
+ }
482
+
483
+ $result .= $this->nl . $this->p($node);
484
+ } else {
485
+ $result .= $this->nl;
486
+ }
487
+ if ($trailingComma || $idx !== $lastIdx) {
488
+ $result .= ',';
489
+ }
490
+ }
491
+
492
+ $this->outdent();
493
+ return $result;
494
+ }
495
+
496
+ /**
497
+ * Prints reformatted text of the passed comments.
498
+ *
499
+ * @param Comment[] $comments List of comments
500
+ *
501
+ * @return string Reformatted text of comments
502
+ */
503
+ protected function pComments(array $comments): string {
504
+ $formattedComments = [];
505
+
506
+ foreach ($comments as $comment) {
507
+ $formattedComments[] = str_replace("\n", $this->nl, $comment->getReformattedText());
508
+ }
509
+
510
+ return implode($this->nl, $formattedComments);
511
+ }
512
+
513
+ /**
514
+ * Perform a format-preserving pretty print of an AST.
515
+ *
516
+ * The format preservation is best effort. For some changes to the AST the formatting will not
517
+ * be preserved (at least not locally).
518
+ *
519
+ * In order to use this method a number of prerequisites must be satisfied:
520
+ * * The startTokenPos and endTokenPos attributes in the lexer must be enabled.
521
+ * * The CloningVisitor must be run on the AST prior to modification.
522
+ * * The original tokens must be provided, using the getTokens() method on the lexer.
523
+ *
524
+ * @param Node[] $stmts Modified AST with links to original AST
525
+ * @param Node[] $origStmts Original AST with token offset information
526
+ * @param Token[] $origTokens Tokens of the original code
527
+ */
528
+ public function printFormatPreserving(array $stmts, array $origStmts, array $origTokens): string {
529
+ $this->initializeNodeListDiffer();
530
+ $this->initializeLabelCharMap();
531
+ $this->initializeFixupMap();
532
+ $this->initializeRemovalMap();
533
+ $this->initializeInsertionMap();
534
+ $this->initializeListInsertionMap();
535
+ $this->initializeEmptyListInsertionMap();
536
+ $this->initializeModifierChangeMap();
537
+
538
+ $this->resetState();
539
+ $this->origTokens = new TokenStream($origTokens);
540
+
541
+ $this->preprocessNodes($stmts);
542
+
543
+ $pos = 0;
544
+ $result = $this->pArray($stmts, $origStmts, $pos, 0, 'File', 'stmts', null);
545
+ if (null !== $result) {
546
+ $result .= $this->origTokens->getTokenCode($pos, count($origTokens) - 1, 0);
547
+ } else {
548
+ // Fallback
549
+ // TODO Add <?php properly
550
+ $result = "<?php" . $this->newline . $this->pStmts($stmts, false);
551
+ }
552
+
553
+ return $this->handleMagicTokens($result);
554
+ }
555
+
556
+ protected function pFallback(Node $node, int $precedence, int $lhsPrecedence): string {
557
+ return $this->{'p' . $node->getType()}($node, $precedence, $lhsPrecedence);
558
+ }
559
+
560
+ /**
561
+ * Pretty prints a node.
562
+ *
563
+ * This method also handles formatting preservation for nodes.
564
+ *
565
+ * @param Node $node Node to be pretty printed
566
+ * @param int $precedence Precedence of parent operator
567
+ * @param int $lhsPrecedence Precedence for unary operator on LHS of binary operator
568
+ * @param bool $parentFormatPreserved Whether parent node has preserved formatting
569
+ *
570
+ * @return string Pretty printed node
571
+ */
572
+ protected function p(
573
+ Node $node, int $precedence = self::MAX_PRECEDENCE, int $lhsPrecedence = self::MAX_PRECEDENCE,
574
+ bool $parentFormatPreserved = false
575
+ ): string {
576
+ // No orig tokens means this is a normal pretty print without preservation of formatting
577
+ if (!$this->origTokens) {
578
+ return $this->{'p' . $node->getType()}($node, $precedence, $lhsPrecedence);
579
+ }
580
+
581
+ /** @var Node|null $origNode */
582
+ $origNode = $node->getAttribute('origNode');
583
+ if (null === $origNode) {
584
+ return $this->pFallback($node, $precedence, $lhsPrecedence);
585
+ }
586
+
587
+ $class = \get_class($node);
588
+ \assert($class === \get_class($origNode));
589
+
590
+ $startPos = $origNode->getStartTokenPos();
591
+ $endPos = $origNode->getEndTokenPos();
592
+ \assert($startPos >= 0 && $endPos >= 0);
593
+
594
+ $fallbackNode = $node;
595
+ if ($node instanceof Expr\New_ && $node->class instanceof Stmt\Class_) {
596
+ // Normalize node structure of anonymous classes
597
+ assert($origNode instanceof Expr\New_);
598
+ $node = PrintableNewAnonClassNode::fromNewNode($node);
599
+ $origNode = PrintableNewAnonClassNode::fromNewNode($origNode);
600
+ $class = PrintableNewAnonClassNode::class;
601
+ }
602
+
603
+ // InlineHTML node does not contain closing and opening PHP tags. If the parent formatting
604
+ // is not preserved, then we need to use the fallback code to make sure the tags are
605
+ // printed.
606
+ if ($node instanceof Stmt\InlineHTML && !$parentFormatPreserved) {
607
+ return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence);
608
+ }
609
+
610
+ $indentAdjustment = $this->indentLevel - $this->origTokens->getIndentationBefore($startPos);
611
+
612
+ $type = $node->getType();
613
+ $fixupInfo = $this->fixupMap[$class] ?? null;
614
+
615
+ $result = '';
616
+ $pos = $startPos;
617
+ foreach ($node->getSubNodeNames() as $subNodeName) {
618
+ $subNode = $node->$subNodeName;
619
+ $origSubNode = $origNode->$subNodeName;
620
+
621
+ if ((!$subNode instanceof Node && $subNode !== null)
622
+ || (!$origSubNode instanceof Node && $origSubNode !== null)
623
+ ) {
624
+ if ($subNode === $origSubNode) {
625
+ // Unchanged, can reuse old code
626
+ continue;
627
+ }
628
+
629
+ if (is_array($subNode) && is_array($origSubNode)) {
630
+ // Array subnode changed, we might be able to reconstruct it
631
+ $listResult = $this->pArray(
632
+ $subNode, $origSubNode, $pos, $indentAdjustment, $class, $subNodeName,
633
+ $fixupInfo[$subNodeName] ?? null
634
+ );
635
+ if (null === $listResult) {
636
+ return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence);
637
+ }
638
+
639
+ $result .= $listResult;
640
+ continue;
641
+ }
642
+
643
+ // Check if this is a modifier change
644
+ $key = $class . '->' . $subNodeName;
645
+ if (!isset($this->modifierChangeMap[$key])) {
646
+ return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence);
647
+ }
648
+
649
+ [$printFn, $findToken] = $this->modifierChangeMap[$key];
650
+ $result .= $this->$printFn($subNode);
651
+ $pos = $this->origTokens->findRight($pos, $findToken);
652
+ continue;
653
+ }
654
+
655
+ $extraLeft = '';
656
+ $extraRight = '';
657
+ if ($origSubNode !== null) {
658
+ $subStartPos = $origSubNode->getStartTokenPos();
659
+ $subEndPos = $origSubNode->getEndTokenPos();
660
+ \assert($subStartPos >= 0 && $subEndPos >= 0);
661
+ } else {
662
+ if ($subNode === null) {
663
+ // Both null, nothing to do
664
+ continue;
665
+ }
666
+
667
+ // A node has been inserted, check if we have insertion information for it
668
+ $key = $type . '->' . $subNodeName;
669
+ if (!isset($this->insertionMap[$key])) {
670
+ return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence);
671
+ }
672
+
673
+ list($findToken, $beforeToken, $extraLeft, $extraRight) = $this->insertionMap[$key];
674
+ if (null !== $findToken) {
675
+ $subStartPos = $this->origTokens->findRight($pos, $findToken)
676
+ + (int) !$beforeToken;
677
+ } else {
678
+ $subStartPos = $pos;
679
+ }
680
+
681
+ if (null === $extraLeft && null !== $extraRight) {
682
+ // If inserting on the right only, skipping whitespace looks better
683
+ $subStartPos = $this->origTokens->skipRightWhitespace($subStartPos);
684
+ }
685
+ $subEndPos = $subStartPos - 1;
686
+ }
687
+
688
+ if (null === $subNode) {
689
+ // A node has been removed, check if we have removal information for it
690
+ $key = $type . '->' . $subNodeName;
691
+ if (!isset($this->removalMap[$key])) {
692
+ return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence);
693
+ }
694
+
695
+ // Adjust positions to account for additional tokens that must be skipped
696
+ $removalInfo = $this->removalMap[$key];
697
+ if (isset($removalInfo['left'])) {
698
+ $subStartPos = $this->origTokens->skipLeft($subStartPos - 1, $removalInfo['left']) + 1;
699
+ }
700
+ if (isset($removalInfo['right'])) {
701
+ $subEndPos = $this->origTokens->skipRight($subEndPos + 1, $removalInfo['right']) - 1;
702
+ }
703
+ }
704
+
705
+ $result .= $this->origTokens->getTokenCode($pos, $subStartPos, $indentAdjustment);
706
+
707
+ if (null !== $subNode) {
708
+ $result .= $extraLeft;
709
+
710
+ $origIndentLevel = $this->indentLevel;
711
+ $this->setIndentLevel($this->origTokens->getIndentationBefore($subStartPos) + $indentAdjustment);
712
+
713
+ // If it's the same node that was previously in this position, it certainly doesn't
714
+ // need fixup. It's important to check this here, because our fixup checks are more
715
+ // conservative than strictly necessary.
716
+ if (isset($fixupInfo[$subNodeName])
717
+ && $subNode->getAttribute('origNode') !== $origSubNode
718
+ ) {
719
+ $fixup = $fixupInfo[$subNodeName];
720
+ $res = $this->pFixup($fixup, $subNode, $class, $subStartPos, $subEndPos);
721
+ } else {
722
+ $res = $this->p($subNode, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, true);
723
+ }
724
+
725
+ $this->safeAppend($result, $res);
726
+ $this->setIndentLevel($origIndentLevel);
727
+
728
+ $result .= $extraRight;
729
+ }
730
+
731
+ $pos = $subEndPos + 1;
732
+ }
733
+
734
+ $result .= $this->origTokens->getTokenCode($pos, $endPos + 1, $indentAdjustment);
735
+ return $result;
736
+ }
737
+
738
+ /**
739
+ * Perform a format-preserving pretty print of an array.
740
+ *
741
+ * @param Node[] $nodes New nodes
742
+ * @param Node[] $origNodes Original nodes
743
+ * @param int $pos Current token position (updated by reference)
744
+ * @param int $indentAdjustment Adjustment for indentation
745
+ * @param string $parentNodeClass Class of the containing node.
746
+ * @param string $subNodeName Name of array subnode.
747
+ * @param null|int $fixup Fixup information for array item nodes
748
+ *
749
+ * @return null|string Result of pretty print or null if cannot preserve formatting
750
+ */
751
+ protected function pArray(
752
+ array $nodes, array $origNodes, int &$pos, int $indentAdjustment,
753
+ string $parentNodeClass, string $subNodeName, ?int $fixup
754
+ ): ?string {
755
+ $diff = $this->nodeListDiffer->diffWithReplacements($origNodes, $nodes);
756
+
757
+ $mapKey = $parentNodeClass . '->' . $subNodeName;
758
+ $insertStr = $this->listInsertionMap[$mapKey] ?? null;
759
+ $isStmtList = $subNodeName === 'stmts';
760
+
761
+ $beforeFirstKeepOrReplace = true;
762
+ $skipRemovedNode = false;
763
+ $delayedAdd = [];
764
+ $lastElemIndentLevel = $this->indentLevel;
765
+
766
+ $insertNewline = false;
767
+ if ($insertStr === "\n") {
768
+ $insertStr = '';
769
+ $insertNewline = true;
770
+ }
771
+
772
+ if ($isStmtList && \count($origNodes) === 1 && \count($nodes) !== 1) {
773
+ $startPos = $origNodes[0]->getStartTokenPos();
774
+ $endPos = $origNodes[0]->getEndTokenPos();
775
+ \assert($startPos >= 0 && $endPos >= 0);
776
+ if (!$this->origTokens->haveBraces($startPos, $endPos)) {
777
+ // This was a single statement without braces, but either additional statements
778
+ // have been added, or the single statement has been removed. This requires the
779
+ // addition of braces. For now fall back.
780
+ // TODO: Try to preserve formatting
781
+ return null;
782
+ }
783
+ }
784
+
785
+ $result = '';
786
+ foreach ($diff as $i => $diffElem) {
787
+ $diffType = $diffElem->type;
788
+ /** @var Node|string|null $arrItem */
789
+ $arrItem = $diffElem->new;
790
+ /** @var Node|string|null $origArrItem */
791
+ $origArrItem = $diffElem->old;
792
+
793
+ if ($diffType === DiffElem::TYPE_KEEP || $diffType === DiffElem::TYPE_REPLACE) {
794
+ $beforeFirstKeepOrReplace = false;
795
+
796
+ if ($origArrItem === null || $arrItem === null) {
797
+ // We can only handle the case where both are null
798
+ if ($origArrItem === $arrItem) {
799
+ continue;
800
+ }
801
+ return null;
802
+ }
803
+
804
+ if (!$arrItem instanceof Node || !$origArrItem instanceof Node) {
805
+ // We can only deal with nodes. This can occur for Names, which use string arrays.
806
+ return null;
807
+ }
808
+
809
+ $itemStartPos = $origArrItem->getStartTokenPos();
810
+ $itemEndPos = $origArrItem->getEndTokenPos();
811
+ \assert($itemStartPos >= 0 && $itemEndPos >= 0 && $itemStartPos >= $pos);
812
+
813
+ $origIndentLevel = $this->indentLevel;
814
+ $lastElemIndentLevel = $this->origTokens->getIndentationBefore($itemStartPos) + $indentAdjustment;
815
+ $this->setIndentLevel($lastElemIndentLevel);
816
+
817
+ $comments = $arrItem->getComments();
818
+ $origComments = $origArrItem->getComments();
819
+ $commentStartPos = $origComments ? $origComments[0]->getStartTokenPos() : $itemStartPos;
820
+ \assert($commentStartPos >= 0);
821
+
822
+ if ($commentStartPos < $pos) {
823
+ // Comments may be assigned to multiple nodes if they start at the same position.
824
+ // Make sure we don't try to print them multiple times.
825
+ $commentStartPos = $itemStartPos;
826
+ }
827
+
828
+ if ($skipRemovedNode) {
829
+ if ($isStmtList && $this->origTokens->haveTagInRange($pos, $itemStartPos)) {
830
+ // We'd remove an opening/closing PHP tag.
831
+ // TODO: Preserve formatting.
832
+ $this->setIndentLevel($origIndentLevel);
833
+ return null;
834
+ }
835
+ } else {
836
+ $result .= $this->origTokens->getTokenCode(
837
+ $pos, $commentStartPos, $indentAdjustment);
838
+ }
839
+
840
+ if (!empty($delayedAdd)) {
841
+ /** @var Node $delayedAddNode */
842
+ foreach ($delayedAdd as $delayedAddNode) {
843
+ if ($insertNewline) {
844
+ $delayedAddComments = $delayedAddNode->getComments();
845
+ if ($delayedAddComments) {
846
+ $result .= $this->pComments($delayedAddComments) . $this->nl;
847
+ }
848
+ }
849
+
850
+ $this->safeAppend($result, $this->p($delayedAddNode, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, true));
851
+
852
+ if ($insertNewline) {
853
+ $result .= $insertStr . $this->nl;
854
+ } else {
855
+ $result .= $insertStr;
856
+ }
857
+ }
858
+
859
+ $delayedAdd = [];
860
+ }
861
+
862
+ if ($comments !== $origComments) {
863
+ if ($comments) {
864
+ $result .= $this->pComments($comments) . $this->nl;
865
+ }
866
+ } else {
867
+ $result .= $this->origTokens->getTokenCode(
868
+ $commentStartPos, $itemStartPos, $indentAdjustment);
869
+ }
870
+
871
+ // If we had to remove anything, we have done so now.
872
+ $skipRemovedNode = false;
873
+ } elseif ($diffType === DiffElem::TYPE_ADD) {
874
+ if (null === $insertStr) {
875
+ // We don't have insertion information for this list type
876
+ return null;
877
+ }
878
+
879
+ if (!$arrItem instanceof Node) {
880
+ // We only support list insertion of nodes.
881
+ return null;
882
+ }
883
+
884
+ // We go multiline if the original code was multiline,
885
+ // or if it's an array item with a comment above it.
886
+ // Match always uses multiline formatting.
887
+ if ($insertStr === ', ' &&
888
+ ($this->isMultiline($origNodes) || $arrItem->getComments() ||
889
+ $parentNodeClass === Expr\Match_::class)
890
+ ) {
891
+ $insertStr = ',';
892
+ $insertNewline = true;
893
+ }
894
+
895
+ if ($beforeFirstKeepOrReplace) {
896
+ // Will be inserted at the next "replace" or "keep" element
897
+ $delayedAdd[] = $arrItem;
898
+ continue;
899
+ }
900
+
901
+ $itemStartPos = $pos;
902
+ $itemEndPos = $pos - 1;
903
+
904
+ $origIndentLevel = $this->indentLevel;
905
+ $this->setIndentLevel($lastElemIndentLevel);
906
+
907
+ if ($insertNewline) {
908
+ $result .= $insertStr . $this->nl;
909
+ $comments = $arrItem->getComments();
910
+ if ($comments) {
911
+ $result .= $this->pComments($comments) . $this->nl;
912
+ }
913
+ } else {
914
+ $result .= $insertStr;
915
+ }
916
+ } elseif ($diffType === DiffElem::TYPE_REMOVE) {
917
+ if (!$origArrItem instanceof Node) {
918
+ // We only support removal for nodes
919
+ return null;
920
+ }
921
+
922
+ $itemStartPos = $origArrItem->getStartTokenPos();
923
+ $itemEndPos = $origArrItem->getEndTokenPos();
924
+ \assert($itemStartPos >= 0 && $itemEndPos >= 0);
925
+
926
+ // Consider comments part of the node.
927
+ $origComments = $origArrItem->getComments();
928
+ if ($origComments) {
929
+ $itemStartPos = $origComments[0]->getStartTokenPos();
930
+ }
931
+
932
+ if ($i === 0) {
933
+ // If we're removing from the start, keep the tokens before the node and drop those after it,
934
+ // instead of the other way around.
935
+ $result .= $this->origTokens->getTokenCode(
936
+ $pos, $itemStartPos, $indentAdjustment);
937
+ $skipRemovedNode = true;
938
+ } else {
939
+ if ($isStmtList && $this->origTokens->haveTagInRange($pos, $itemStartPos)) {
940
+ // We'd remove an opening/closing PHP tag.
941
+ // TODO: Preserve formatting.
942
+ return null;
943
+ }
944
+ }
945
+
946
+ $pos = $itemEndPos + 1;
947
+ continue;
948
+ } else {
949
+ throw new \Exception("Shouldn't happen");
950
+ }
951
+
952
+ if (null !== $fixup && $arrItem->getAttribute('origNode') !== $origArrItem) {
953
+ $res = $this->pFixup($fixup, $arrItem, null, $itemStartPos, $itemEndPos);
954
+ } else {
955
+ $res = $this->p($arrItem, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, true);
956
+ }
957
+ $this->safeAppend($result, $res);
958
+
959
+ $this->setIndentLevel($origIndentLevel);
960
+ $pos = $itemEndPos + 1;
961
+ }
962
+
963
+ if ($skipRemovedNode) {
964
+ // TODO: Support removing single node.
965
+ return null;
966
+ }
967
+
968
+ if (!empty($delayedAdd)) {
969
+ if (!isset($this->emptyListInsertionMap[$mapKey])) {
970
+ return null;
971
+ }
972
+
973
+ list($findToken, $extraLeft, $extraRight) = $this->emptyListInsertionMap[$mapKey];
974
+ if (null !== $findToken) {
975
+ $insertPos = $this->origTokens->findRight($pos, $findToken) + 1;
976
+ $result .= $this->origTokens->getTokenCode($pos, $insertPos, $indentAdjustment);
977
+ $pos = $insertPos;
978
+ }
979
+
980
+ $first = true;
981
+ $result .= $extraLeft;
982
+ foreach ($delayedAdd as $delayedAddNode) {
983
+ if (!$first) {
984
+ $result .= $insertStr;
985
+ if ($insertNewline) {
986
+ $result .= $this->nl;
987
+ }
988
+ }
989
+ $result .= $this->p($delayedAddNode, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, true);
990
+ $first = false;
991
+ }
992
+ $result .= $extraRight === "\n" ? $this->nl : $extraRight;
993
+ }
994
+
995
+ return $result;
996
+ }
997
+
998
+ /**
999
+ * Print node with fixups.
1000
+ *
1001
+ * Fixups here refer to the addition of extra parentheses, braces or other characters, that
1002
+ * are required to preserve program semantics in a certain context (e.g. to maintain precedence
1003
+ * or because only certain expressions are allowed in certain places).
1004
+ *
1005
+ * @param int $fixup Fixup type
1006
+ * @param Node $subNode Subnode to print
1007
+ * @param string|null $parentClass Class of parent node
1008
+ * @param int $subStartPos Original start pos of subnode
1009
+ * @param int $subEndPos Original end pos of subnode
1010
+ *
1011
+ * @return string Result of fixed-up print of subnode
1012
+ */
1013
+ protected function pFixup(int $fixup, Node $subNode, ?string $parentClass, int $subStartPos, int $subEndPos): string {
1014
+ switch ($fixup) {
1015
+ case self::FIXUP_PREC_LEFT:
1016
+ // We use a conservative approximation where lhsPrecedence == precedence.
1017
+ if (!$this->origTokens->haveParens($subStartPos, $subEndPos)) {
1018
+ $precedence = $this->precedenceMap[$parentClass][1];
1019
+ return $this->p($subNode, $precedence, $precedence);
1020
+ }
1021
+ break;
1022
+ case self::FIXUP_PREC_RIGHT:
1023
+ if (!$this->origTokens->haveParens($subStartPos, $subEndPos)) {
1024
+ $precedence = $this->precedenceMap[$parentClass][2];
1025
+ return $this->p($subNode, $precedence, $precedence);
1026
+ }
1027
+ break;
1028
+ case self::FIXUP_PREC_UNARY:
1029
+ if (!$this->origTokens->haveParens($subStartPos, $subEndPos)) {
1030
+ $precedence = $this->precedenceMap[$parentClass][0];
1031
+ return $this->p($subNode, $precedence, $precedence);
1032
+ }
1033
+ break;
1034
+ case self::FIXUP_CALL_LHS:
1035
+ if ($this->callLhsRequiresParens($subNode)
1036
+ && !$this->origTokens->haveParens($subStartPos, $subEndPos)
1037
+ ) {
1038
+ return '(' . $this->p($subNode) . ')';
1039
+ }
1040
+ break;
1041
+ case self::FIXUP_DEREF_LHS:
1042
+ if ($this->dereferenceLhsRequiresParens($subNode)
1043
+ && !$this->origTokens->haveParens($subStartPos, $subEndPos)
1044
+ ) {
1045
+ return '(' . $this->p($subNode) . ')';
1046
+ }
1047
+ break;
1048
+ case self::FIXUP_STATIC_DEREF_LHS:
1049
+ if ($this->staticDereferenceLhsRequiresParens($subNode)
1050
+ && !$this->origTokens->haveParens($subStartPos, $subEndPos)
1051
+ ) {
1052
+ return '(' . $this->p($subNode) . ')';
1053
+ }
1054
+ break;
1055
+ case self::FIXUP_NEW:
1056
+ if ($this->newOperandRequiresParens($subNode)
1057
+ && !$this->origTokens->haveParens($subStartPos, $subEndPos)) {
1058
+ return '(' . $this->p($subNode) . ')';
1059
+ }
1060
+ break;
1061
+ case self::FIXUP_BRACED_NAME:
1062
+ case self::FIXUP_VAR_BRACED_NAME:
1063
+ if ($subNode instanceof Expr
1064
+ && !$this->origTokens->haveBraces($subStartPos, $subEndPos)
1065
+ ) {
1066
+ return ($fixup === self::FIXUP_VAR_BRACED_NAME ? '$' : '')
1067
+ . '{' . $this->p($subNode) . '}';
1068
+ }
1069
+ break;
1070
+ case self::FIXUP_ENCAPSED:
1071
+ if (!$subNode instanceof Node\InterpolatedStringPart
1072
+ && !$this->origTokens->haveBraces($subStartPos, $subEndPos)
1073
+ ) {
1074
+ return '{' . $this->p($subNode) . '}';
1075
+ }
1076
+ break;
1077
+ default:
1078
+ throw new \Exception('Cannot happen');
1079
+ }
1080
+
1081
+ // Nothing special to do
1082
+ return $this->p($subNode);
1083
+ }
1084
+
1085
+ /**
1086
+ * Appends to a string, ensuring whitespace between label characters.
1087
+ *
1088
+ * Example: "echo" and "$x" result in "echo$x", but "echo" and "x" result in "echo x".
1089
+ * Without safeAppend the result would be "echox", which does not preserve semantics.
1090
+ */
1091
+ protected function safeAppend(string &$str, string $append): void {
1092
+ if ($str === "") {
1093
+ $str = $append;
1094
+ return;
1095
+ }
1096
+
1097
+ if ($append === "") {
1098
+ return;
1099
+ }
1100
+
1101
+ if (!$this->labelCharMap[$append[0]]
1102
+ || !$this->labelCharMap[$str[\strlen($str) - 1]]) {
1103
+ $str .= $append;
1104
+ } else {
1105
+ $str .= " " . $append;
1106
+ }
1107
+ }
1108
+
1109
+ /**
1110
+ * Determines whether the LHS of a call must be wrapped in parenthesis.
1111
+ *
1112
+ * @param Node $node LHS of a call
1113
+ *
1114
+ * @return bool Whether parentheses are required
1115
+ */
1116
+ protected function callLhsRequiresParens(Node $node): bool {
1117
+ return !($node instanceof Node\Name
1118
+ || $node instanceof Expr\Variable
1119
+ || $node instanceof Expr\ArrayDimFetch
1120
+ || $node instanceof Expr\FuncCall
1121
+ || $node instanceof Expr\MethodCall
1122
+ || $node instanceof Expr\NullsafeMethodCall
1123
+ || $node instanceof Expr\StaticCall
1124
+ || $node instanceof Expr\Array_);
1125
+ }
1126
+
1127
+ /**
1128
+ * Determines whether the LHS of an array/object operation must be wrapped in parentheses.
1129
+ *
1130
+ * @param Node $node LHS of dereferencing operation
1131
+ *
1132
+ * @return bool Whether parentheses are required
1133
+ */
1134
+ protected function dereferenceLhsRequiresParens(Node $node): bool {
1135
+ // A constant can occur on the LHS of an array/object deref, but not a static deref.
1136
+ return $this->staticDereferenceLhsRequiresParens($node)
1137
+ && !$node instanceof Expr\ConstFetch;
1138
+ }
1139
+
1140
+ /**
1141
+ * Determines whether the LHS of a static operation must be wrapped in parentheses.
1142
+ *
1143
+ * @param Node $node LHS of dereferencing operation
1144
+ *
1145
+ * @return bool Whether parentheses are required
1146
+ */
1147
+ protected function staticDereferenceLhsRequiresParens(Node $node): bool {
1148
+ return !($node instanceof Expr\Variable
1149
+ || $node instanceof Node\Name
1150
+ || $node instanceof Expr\ArrayDimFetch
1151
+ || $node instanceof Expr\PropertyFetch
1152
+ || $node instanceof Expr\NullsafePropertyFetch
1153
+ || $node instanceof Expr\StaticPropertyFetch
1154
+ || $node instanceof Expr\FuncCall
1155
+ || $node instanceof Expr\MethodCall
1156
+ || $node instanceof Expr\NullsafeMethodCall
1157
+ || $node instanceof Expr\StaticCall
1158
+ || $node instanceof Expr\Array_
1159
+ || $node instanceof Scalar\String_
1160
+ || $node instanceof Expr\ClassConstFetch);
1161
+ }
1162
+
1163
+ /**
1164
+ * Determines whether an expression used in "new" or "instanceof" requires parentheses.
1165
+ *
1166
+ * @param Node $node New or instanceof operand
1167
+ *
1168
+ * @return bool Whether parentheses are required
1169
+ */
1170
+ protected function newOperandRequiresParens(Node $node): bool {
1171
+ if ($node instanceof Node\Name || $node instanceof Expr\Variable) {
1172
+ return false;
1173
+ }
1174
+ if ($node instanceof Expr\ArrayDimFetch || $node instanceof Expr\PropertyFetch ||
1175
+ $node instanceof Expr\NullsafePropertyFetch
1176
+ ) {
1177
+ return $this->newOperandRequiresParens($node->var);
1178
+ }
1179
+ if ($node instanceof Expr\StaticPropertyFetch) {
1180
+ return $this->newOperandRequiresParens($node->class);
1181
+ }
1182
+ return true;
1183
+ }
1184
+
1185
+ /**
1186
+ * Print modifiers, including trailing whitespace.
1187
+ *
1188
+ * @param int $modifiers Modifier mask to print
1189
+ *
1190
+ * @return string Printed modifiers
1191
+ */
1192
+ protected function pModifiers(int $modifiers): string {
1193
+ return ($modifiers & Modifiers::FINAL ? 'final ' : '')
1194
+ . ($modifiers & Modifiers::ABSTRACT ? 'abstract ' : '')
1195
+ . ($modifiers & Modifiers::PUBLIC ? 'public ' : '')
1196
+ . ($modifiers & Modifiers::PROTECTED ? 'protected ' : '')
1197
+ . ($modifiers & Modifiers::PRIVATE ? 'private ' : '')
1198
+ . ($modifiers & Modifiers::STATIC ? 'static ' : '')
1199
+ . ($modifiers & Modifiers::READONLY ? 'readonly ' : '');
1200
+ }
1201
+
1202
+ protected function pStatic(bool $static): string {
1203
+ return $static ? 'static ' : '';
1204
+ }
1205
+
1206
+ /**
1207
+ * Determine whether a list of nodes uses multiline formatting.
1208
+ *
1209
+ * @param (Node|null)[] $nodes Node list
1210
+ *
1211
+ * @return bool Whether multiline formatting is used
1212
+ */
1213
+ protected function isMultiline(array $nodes): bool {
1214
+ if (\count($nodes) < 2) {
1215
+ return false;
1216
+ }
1217
+
1218
+ $pos = -1;
1219
+ foreach ($nodes as $node) {
1220
+ if (null === $node) {
1221
+ continue;
1222
+ }
1223
+
1224
+ $endPos = $node->getEndTokenPos() + 1;
1225
+ if ($pos >= 0) {
1226
+ $text = $this->origTokens->getTokenCode($pos, $endPos, 0);
1227
+ if (false === strpos($text, "\n")) {
1228
+ // We require that a newline is present between *every* item. If the formatting
1229
+ // is inconsistent, with only some items having newlines, we don't consider it
1230
+ // as multiline
1231
+ return false;
1232
+ }
1233
+ }
1234
+ $pos = $endPos;
1235
+ }
1236
+
1237
+ return true;
1238
+ }
1239
+
1240
+ /**
1241
+ * Lazily initializes label char map.
1242
+ *
1243
+ * The label char map determines whether a certain character may occur in a label.
1244
+ */
1245
+ protected function initializeLabelCharMap(): void {
1246
+ if (isset($this->labelCharMap)) {
1247
+ return;
1248
+ }
1249
+
1250
+ $this->labelCharMap = [];
1251
+ for ($i = 0; $i < 256; $i++) {
1252
+ $chr = chr($i);
1253
+ $this->labelCharMap[$chr] = $i >= 0x80 || ctype_alnum($chr);
1254
+ }
1255
+
1256
+ if ($this->phpVersion->allowsDelInIdentifiers()) {
1257
+ $this->labelCharMap["\x7f"] = true;
1258
+ }
1259
+ }
1260
+
1261
+ /**
1262
+ * Lazily initializes node list differ.
1263
+ *
1264
+ * The node list differ is used to determine differences between two array subnodes.
1265
+ */
1266
+ protected function initializeNodeListDiffer(): void {
1267
+ if (isset($this->nodeListDiffer)) {
1268
+ return;
1269
+ }
1270
+
1271
+ $this->nodeListDiffer = new Internal\Differ(function ($a, $b) {
1272
+ if ($a instanceof Node && $b instanceof Node) {
1273
+ return $a === $b->getAttribute('origNode');
1274
+ }
1275
+ // Can happen for array destructuring
1276
+ return $a === null && $b === null;
1277
+ });
1278
+ }
1279
+
1280
+ /**
1281
+ * Lazily initializes fixup map.
1282
+ *
1283
+ * The fixup map is used to determine whether a certain subnode of a certain node may require
1284
+ * some kind of "fixup" operation, e.g. the addition of parenthesis or braces.
1285
+ */
1286
+ protected function initializeFixupMap(): void {
1287
+ if (isset($this->fixupMap)) {
1288
+ return;
1289
+ }
1290
+
1291
+ $this->fixupMap = [
1292
+ Expr\Instanceof_::class => [
1293
+ 'expr' => self::FIXUP_PREC_UNARY,
1294
+ 'class' => self::FIXUP_NEW,
1295
+ ],
1296
+ Expr\Ternary::class => [
1297
+ 'cond' => self::FIXUP_PREC_LEFT,
1298
+ 'else' => self::FIXUP_PREC_RIGHT,
1299
+ ],
1300
+ Expr\Yield_::class => ['value' => self::FIXUP_PREC_UNARY],
1301
+
1302
+ Expr\FuncCall::class => ['name' => self::FIXUP_CALL_LHS],
1303
+ Expr\StaticCall::class => ['class' => self::FIXUP_STATIC_DEREF_LHS],
1304
+ Expr\ArrayDimFetch::class => ['var' => self::FIXUP_DEREF_LHS],
1305
+ Expr\ClassConstFetch::class => [
1306
+ 'class' => self::FIXUP_STATIC_DEREF_LHS,
1307
+ 'name' => self::FIXUP_BRACED_NAME,
1308
+ ],
1309
+ Expr\New_::class => ['class' => self::FIXUP_NEW],
1310
+ Expr\MethodCall::class => [
1311
+ 'var' => self::FIXUP_DEREF_LHS,
1312
+ 'name' => self::FIXUP_BRACED_NAME,
1313
+ ],
1314
+ Expr\NullsafeMethodCall::class => [
1315
+ 'var' => self::FIXUP_DEREF_LHS,
1316
+ 'name' => self::FIXUP_BRACED_NAME,
1317
+ ],
1318
+ Expr\StaticPropertyFetch::class => [
1319
+ 'class' => self::FIXUP_STATIC_DEREF_LHS,
1320
+ 'name' => self::FIXUP_VAR_BRACED_NAME,
1321
+ ],
1322
+ Expr\PropertyFetch::class => [
1323
+ 'var' => self::FIXUP_DEREF_LHS,
1324
+ 'name' => self::FIXUP_BRACED_NAME,
1325
+ ],
1326
+ Expr\NullsafePropertyFetch::class => [
1327
+ 'var' => self::FIXUP_DEREF_LHS,
1328
+ 'name' => self::FIXUP_BRACED_NAME,
1329
+ ],
1330
+ Scalar\InterpolatedString::class => [
1331
+ 'parts' => self::FIXUP_ENCAPSED,
1332
+ ],
1333
+ ];
1334
+
1335
+ $binaryOps = [
1336
+ BinaryOp\Pow::class, BinaryOp\Mul::class, BinaryOp\Div::class, BinaryOp\Mod::class,
1337
+ BinaryOp\Plus::class, BinaryOp\Minus::class, BinaryOp\Concat::class,
1338
+ BinaryOp\ShiftLeft::class, BinaryOp\ShiftRight::class, BinaryOp\Smaller::class,
1339
+ BinaryOp\SmallerOrEqual::class, BinaryOp\Greater::class, BinaryOp\GreaterOrEqual::class,
1340
+ BinaryOp\Equal::class, BinaryOp\NotEqual::class, BinaryOp\Identical::class,
1341
+ BinaryOp\NotIdentical::class, BinaryOp\Spaceship::class, BinaryOp\BitwiseAnd::class,
1342
+ BinaryOp\BitwiseXor::class, BinaryOp\BitwiseOr::class, BinaryOp\BooleanAnd::class,
1343
+ BinaryOp\BooleanOr::class, BinaryOp\Coalesce::class, BinaryOp\LogicalAnd::class,
1344
+ BinaryOp\LogicalXor::class, BinaryOp\LogicalOr::class,
1345
+ ];
1346
+ foreach ($binaryOps as $binaryOp) {
1347
+ $this->fixupMap[$binaryOp] = [
1348
+ 'left' => self::FIXUP_PREC_LEFT,
1349
+ 'right' => self::FIXUP_PREC_RIGHT
1350
+ ];
1351
+ }
1352
+
1353
+ $prefixOps = [
1354
+ Expr\Clone_::class, Expr\BitwiseNot::class, Expr\BooleanNot::class, Expr\UnaryPlus::class, Expr\UnaryMinus::class,
1355
+ Cast\Int_::class, Cast\Double::class, Cast\String_::class, Cast\Array_::class,
1356
+ Cast\Object_::class, Cast\Bool_::class, Cast\Unset_::class, Expr\ErrorSuppress::class,
1357
+ Expr\YieldFrom::class, Expr\Print_::class, Expr\Include_::class,
1358
+ Expr\Assign::class, Expr\AssignRef::class, AssignOp\Plus::class, AssignOp\Minus::class,
1359
+ AssignOp\Mul::class, AssignOp\Div::class, AssignOp\Concat::class, AssignOp\Mod::class,
1360
+ AssignOp\BitwiseAnd::class, AssignOp\BitwiseOr::class, AssignOp\BitwiseXor::class,
1361
+ AssignOp\ShiftLeft::class, AssignOp\ShiftRight::class, AssignOp\Pow::class, AssignOp\Coalesce::class,
1362
+ Expr\ArrowFunction::class, Expr\Throw_::class,
1363
+ ];
1364
+ foreach ($prefixOps as $prefixOp) {
1365
+ $this->fixupMap[$prefixOp] = ['expr' => self::FIXUP_PREC_UNARY];
1366
+ }
1367
+ }
1368
+
1369
+ /**
1370
+ * Lazily initializes the removal map.
1371
+ *
1372
+ * The removal map is used to determine which additional tokens should be removed when a
1373
+ * certain node is replaced by null.
1374
+ */
1375
+ protected function initializeRemovalMap(): void {
1376
+ if (isset($this->removalMap)) {
1377
+ return;
1378
+ }
1379
+
1380
+ $stripBoth = ['left' => \T_WHITESPACE, 'right' => \T_WHITESPACE];
1381
+ $stripLeft = ['left' => \T_WHITESPACE];
1382
+ $stripRight = ['right' => \T_WHITESPACE];
1383
+ $stripDoubleArrow = ['right' => \T_DOUBLE_ARROW];
1384
+ $stripColon = ['left' => ':'];
1385
+ $stripEquals = ['left' => '='];
1386
+ $this->removalMap = [
1387
+ 'Expr_ArrayDimFetch->dim' => $stripBoth,
1388
+ 'ArrayItem->key' => $stripDoubleArrow,
1389
+ 'Expr_ArrowFunction->returnType' => $stripColon,
1390
+ 'Expr_Closure->returnType' => $stripColon,
1391
+ 'Expr_Exit->expr' => $stripBoth,
1392
+ 'Expr_Ternary->if' => $stripBoth,
1393
+ 'Expr_Yield->key' => $stripDoubleArrow,
1394
+ 'Expr_Yield->value' => $stripBoth,
1395
+ 'Param->type' => $stripRight,
1396
+ 'Param->default' => $stripEquals,
1397
+ 'Stmt_Break->num' => $stripBoth,
1398
+ 'Stmt_Catch->var' => $stripLeft,
1399
+ 'Stmt_ClassConst->type' => $stripRight,
1400
+ 'Stmt_ClassMethod->returnType' => $stripColon,
1401
+ 'Stmt_Class->extends' => ['left' => \T_EXTENDS],
1402
+ 'Stmt_Enum->scalarType' => $stripColon,
1403
+ 'Stmt_EnumCase->expr' => $stripEquals,
1404
+ 'Expr_PrintableNewAnonClass->extends' => ['left' => \T_EXTENDS],
1405
+ 'Stmt_Continue->num' => $stripBoth,
1406
+ 'Stmt_Foreach->keyVar' => $stripDoubleArrow,
1407
+ 'Stmt_Function->returnType' => $stripColon,
1408
+ 'Stmt_If->else' => $stripLeft,
1409
+ 'Stmt_Namespace->name' => $stripLeft,
1410
+ 'Stmt_Property->type' => $stripRight,
1411
+ 'PropertyItem->default' => $stripEquals,
1412
+ 'Stmt_Return->expr' => $stripBoth,
1413
+ 'Stmt_StaticVar->default' => $stripEquals,
1414
+ 'Stmt_TraitUseAdaptation_Alias->newName' => $stripLeft,
1415
+ 'Stmt_TryCatch->finally' => $stripLeft,
1416
+ // 'Stmt_Case->cond': Replace with "default"
1417
+ // 'Stmt_Class->name': Unclear what to do
1418
+ // 'Stmt_Declare->stmts': Not a plain node
1419
+ // 'Stmt_TraitUseAdaptation_Alias->newModifier': Not a plain node
1420
+ ];
1421
+ }
1422
+
1423
+ protected function initializeInsertionMap(): void {
1424
+ if (isset($this->insertionMap)) {
1425
+ return;
1426
+ }
1427
+
1428
+ // TODO: "yield" where both key and value are inserted doesn't work
1429
+ // [$find, $beforeToken, $extraLeft, $extraRight]
1430
+ $this->insertionMap = [
1431
+ 'Expr_ArrayDimFetch->dim' => ['[', false, null, null],
1432
+ 'ArrayItem->key' => [null, false, null, ' => '],
1433
+ 'Expr_ArrowFunction->returnType' => [')', false, ': ', null],
1434
+ 'Expr_Closure->returnType' => [')', false, ': ', null],
1435
+ 'Expr_Ternary->if' => ['?', false, ' ', ' '],
1436
+ 'Expr_Yield->key' => [\T_YIELD, false, null, ' => '],
1437
+ 'Expr_Yield->value' => [\T_YIELD, false, ' ', null],
1438
+ 'Param->type' => [null, false, null, ' '],
1439
+ 'Param->default' => [null, false, ' = ', null],
1440
+ 'Stmt_Break->num' => [\T_BREAK, false, ' ', null],
1441
+ 'Stmt_Catch->var' => [null, false, ' ', null],
1442
+ 'Stmt_ClassMethod->returnType' => [')', false, ': ', null],
1443
+ 'Stmt_ClassConst->type' => [\T_CONST, false, ' ', null],
1444
+ 'Stmt_Class->extends' => [null, false, ' extends ', null],
1445
+ 'Stmt_Enum->scalarType' => [null, false, ' : ', null],
1446
+ 'Stmt_EnumCase->expr' => [null, false, ' = ', null],
1447
+ 'Expr_PrintableNewAnonClass->extends' => [null, false, ' extends ', null],
1448
+ 'Stmt_Continue->num' => [\T_CONTINUE, false, ' ', null],
1449
+ 'Stmt_Foreach->keyVar' => [\T_AS, false, null, ' => '],
1450
+ 'Stmt_Function->returnType' => [')', false, ': ', null],
1451
+ 'Stmt_If->else' => [null, false, ' ', null],
1452
+ 'Stmt_Namespace->name' => [\T_NAMESPACE, false, ' ', null],
1453
+ 'Stmt_Property->type' => [\T_VARIABLE, true, null, ' '],
1454
+ 'PropertyItem->default' => [null, false, ' = ', null],
1455
+ 'Stmt_Return->expr' => [\T_RETURN, false, ' ', null],
1456
+ 'Stmt_StaticVar->default' => [null, false, ' = ', null],
1457
+ //'Stmt_TraitUseAdaptation_Alias->newName' => [T_AS, false, ' ', null], // TODO
1458
+ 'Stmt_TryCatch->finally' => [null, false, ' ', null],
1459
+
1460
+ // 'Expr_Exit->expr': Complicated due to optional ()
1461
+ // 'Stmt_Case->cond': Conversion from default to case
1462
+ // 'Stmt_Class->name': Unclear
1463
+ // 'Stmt_Declare->stmts': Not a proper node
1464
+ // 'Stmt_TraitUseAdaptation_Alias->newModifier': Not a proper node
1465
+ ];
1466
+ }
1467
+
1468
+ protected function initializeListInsertionMap(): void {
1469
+ if (isset($this->listInsertionMap)) {
1470
+ return;
1471
+ }
1472
+
1473
+ $this->listInsertionMap = [
1474
+ // special
1475
+ //'Expr_ShellExec->parts' => '', // TODO These need to be treated more carefully
1476
+ //'Scalar_InterpolatedString->parts' => '',
1477
+ Stmt\Catch_::class . '->types' => '|',
1478
+ UnionType::class . '->types' => '|',
1479
+ IntersectionType::class . '->types' => '&',
1480
+ Stmt\If_::class . '->elseifs' => ' ',
1481
+ Stmt\TryCatch::class . '->catches' => ' ',
1482
+
1483
+ // comma-separated lists
1484
+ Expr\Array_::class . '->items' => ', ',
1485
+ Expr\ArrowFunction::class . '->params' => ', ',
1486
+ Expr\Closure::class . '->params' => ', ',
1487
+ Expr\Closure::class . '->uses' => ', ',
1488
+ Expr\FuncCall::class . '->args' => ', ',
1489
+ Expr\Isset_::class . '->vars' => ', ',
1490
+ Expr\List_::class . '->items' => ', ',
1491
+ Expr\MethodCall::class . '->args' => ', ',
1492
+ Expr\NullsafeMethodCall::class . '->args' => ', ',
1493
+ Expr\New_::class . '->args' => ', ',
1494
+ PrintableNewAnonClassNode::class . '->args' => ', ',
1495
+ Expr\StaticCall::class . '->args' => ', ',
1496
+ Stmt\ClassConst::class . '->consts' => ', ',
1497
+ Stmt\ClassMethod::class . '->params' => ', ',
1498
+ Stmt\Class_::class . '->implements' => ', ',
1499
+ Stmt\Enum_::class . '->implements' => ', ',
1500
+ PrintableNewAnonClassNode::class . '->implements' => ', ',
1501
+ Stmt\Const_::class . '->consts' => ', ',
1502
+ Stmt\Declare_::class . '->declares' => ', ',
1503
+ Stmt\Echo_::class . '->exprs' => ', ',
1504
+ Stmt\For_::class . '->init' => ', ',
1505
+ Stmt\For_::class . '->cond' => ', ',
1506
+ Stmt\For_::class . '->loop' => ', ',
1507
+ Stmt\Function_::class . '->params' => ', ',
1508
+ Stmt\Global_::class . '->vars' => ', ',
1509
+ Stmt\GroupUse::class . '->uses' => ', ',
1510
+ Stmt\Interface_::class . '->extends' => ', ',
1511
+ Expr\Match_::class . '->arms' => ', ',
1512
+ Stmt\Property::class . '->props' => ', ',
1513
+ Stmt\StaticVar::class . '->vars' => ', ',
1514
+ Stmt\TraitUse::class . '->traits' => ', ',
1515
+ Stmt\TraitUseAdaptation\Precedence::class . '->insteadof' => ', ',
1516
+ Stmt\Unset_::class . '->vars' => ', ',
1517
+ Stmt\UseUse::class . '->uses' => ', ',
1518
+ MatchArm::class . '->conds' => ', ',
1519
+ AttributeGroup::class . '->attrs' => ', ',
1520
+
1521
+ // statement lists
1522
+ Expr\Closure::class . '->stmts' => "\n",
1523
+ Stmt\Case_::class . '->stmts' => "\n",
1524
+ Stmt\Catch_::class . '->stmts' => "\n",
1525
+ Stmt\Class_::class . '->stmts' => "\n",
1526
+ Stmt\Enum_::class . '->stmts' => "\n",
1527
+ PrintableNewAnonClassNode::class . '->stmts' => "\n",
1528
+ Stmt\Interface_::class . '->stmts' => "\n",
1529
+ Stmt\Trait_::class . '->stmts' => "\n",
1530
+ Stmt\ClassMethod::class . '->stmts' => "\n",
1531
+ Stmt\Declare_::class . '->stmts' => "\n",
1532
+ Stmt\Do_::class . '->stmts' => "\n",
1533
+ Stmt\ElseIf_::class . '->stmts' => "\n",
1534
+ Stmt\Else_::class . '->stmts' => "\n",
1535
+ Stmt\Finally_::class . '->stmts' => "\n",
1536
+ Stmt\Foreach_::class . '->stmts' => "\n",
1537
+ Stmt\For_::class . '->stmts' => "\n",
1538
+ Stmt\Function_::class . '->stmts' => "\n",
1539
+ Stmt\If_::class . '->stmts' => "\n",
1540
+ Stmt\Namespace_::class . '->stmts' => "\n",
1541
+ Stmt\Block::class . '->stmts' => "\n",
1542
+
1543
+ // Attribute groups
1544
+ Stmt\Class_::class . '->attrGroups' => "\n",
1545
+ Stmt\Enum_::class . '->attrGroups' => "\n",
1546
+ Stmt\EnumCase::class . '->attrGroups' => "\n",
1547
+ Stmt\Interface_::class . '->attrGroups' => "\n",
1548
+ Stmt\Trait_::class . '->attrGroups' => "\n",
1549
+ Stmt\Function_::class . '->attrGroups' => "\n",
1550
+ Stmt\ClassMethod::class . '->attrGroups' => "\n",
1551
+ Stmt\ClassConst::class . '->attrGroups' => "\n",
1552
+ Stmt\Property::class . '->attrGroups' => "\n",
1553
+ PrintableNewAnonClassNode::class . '->attrGroups' => ' ',
1554
+ Expr\Closure::class . '->attrGroups' => ' ',
1555
+ Expr\ArrowFunction::class . '->attrGroups' => ' ',
1556
+ Param::class . '->attrGroups' => ' ',
1557
+ Stmt\Switch_::class . '->cases' => "\n",
1558
+ Stmt\TraitUse::class . '->adaptations' => "\n",
1559
+ Stmt\TryCatch::class . '->stmts' => "\n",
1560
+ Stmt\While_::class . '->stmts' => "\n",
1561
+
1562
+ // dummy for top-level context
1563
+ 'File->stmts' => "\n",
1564
+ ];
1565
+ }
1566
+
1567
+ protected function initializeEmptyListInsertionMap(): void {
1568
+ if (isset($this->emptyListInsertionMap)) {
1569
+ return;
1570
+ }
1571
+
1572
+ // TODO Insertion into empty statement lists.
1573
+
1574
+ // [$find, $extraLeft, $extraRight]
1575
+ $this->emptyListInsertionMap = [
1576
+ Expr\ArrowFunction::class . '->params' => ['(', '', ''],
1577
+ Expr\Closure::class . '->uses' => [')', ' use (', ')'],
1578
+ Expr\Closure::class . '->params' => ['(', '', ''],
1579
+ Expr\FuncCall::class . '->args' => ['(', '', ''],
1580
+ Expr\MethodCall::class . '->args' => ['(', '', ''],
1581
+ Expr\NullsafeMethodCall::class . '->args' => ['(', '', ''],
1582
+ Expr\New_::class . '->args' => ['(', '', ''],
1583
+ PrintableNewAnonClassNode::class . '->args' => ['(', '', ''],
1584
+ PrintableNewAnonClassNode::class . '->implements' => [null, ' implements ', ''],
1585
+ Expr\StaticCall::class . '->args' => ['(', '', ''],
1586
+ Stmt\Class_::class . '->implements' => [null, ' implements ', ''],
1587
+ Stmt\Enum_::class . '->implements' => [null, ' implements ', ''],
1588
+ Stmt\ClassMethod::class . '->params' => ['(', '', ''],
1589
+ Stmt\Interface_::class . '->extends' => [null, ' extends ', ''],
1590
+ Stmt\Function_::class . '->params' => ['(', '', ''],
1591
+ Stmt\Interface_::class . '->attrGroups' => [null, '', "\n"],
1592
+ Stmt\Class_::class . '->attrGroups' => [null, '', "\n"],
1593
+ Stmt\ClassConst::class . '->attrGroups' => [null, '', "\n"],
1594
+ Stmt\ClassMethod::class . '->attrGroups' => [null, '', "\n"],
1595
+ Stmt\Function_::class . '->attrGroups' => [null, '', "\n"],
1596
+ Stmt\Property::class . '->attrGroups' => [null, '', "\n"],
1597
+ Stmt\Trait_::class . '->attrGroups' => [null, '', "\n"],
1598
+ Expr\ArrowFunction::class . '->attrGroups' => [null, '', ' '],
1599
+ Expr\Closure::class . '->attrGroups' => [null, '', ' '],
1600
+ PrintableNewAnonClassNode::class . '->attrGroups' => [\T_NEW, ' ', ''],
1601
+
1602
+ /* These cannot be empty to start with:
1603
+ * Expr_Isset->vars
1604
+ * Stmt_Catch->types
1605
+ * Stmt_Const->consts
1606
+ * Stmt_ClassConst->consts
1607
+ * Stmt_Declare->declares
1608
+ * Stmt_Echo->exprs
1609
+ * Stmt_Global->vars
1610
+ * Stmt_GroupUse->uses
1611
+ * Stmt_Property->props
1612
+ * Stmt_StaticVar->vars
1613
+ * Stmt_TraitUse->traits
1614
+ * Stmt_TraitUseAdaptation_Precedence->insteadof
1615
+ * Stmt_Unset->vars
1616
+ * Stmt_Use->uses
1617
+ * UnionType->types
1618
+ */
1619
+
1620
+ /* TODO
1621
+ * Stmt_If->elseifs
1622
+ * Stmt_TryCatch->catches
1623
+ * Expr_Array->items
1624
+ * Expr_List->items
1625
+ * Stmt_For->init
1626
+ * Stmt_For->cond
1627
+ * Stmt_For->loop
1628
+ */
1629
+ ];
1630
+ }
1631
+
1632
+ protected function initializeModifierChangeMap(): void {
1633
+ if (isset($this->modifierChangeMap)) {
1634
+ return;
1635
+ }
1636
+
1637
+ $this->modifierChangeMap = [
1638
+ Stmt\ClassConst::class . '->flags' => ['pModifiers', \T_CONST],
1639
+ Stmt\ClassMethod::class . '->flags' => ['pModifiers', \T_FUNCTION],
1640
+ Stmt\Class_::class . '->flags' => ['pModifiers', \T_CLASS],
1641
+ Stmt\Property::class . '->flags' => ['pModifiers', \T_VARIABLE],
1642
+ PrintableNewAnonClassNode::class . '->flags' => ['pModifiers', \T_CLASS],
1643
+ Param::class . '->flags' => ['pModifiers', \T_VARIABLE],
1644
+ Expr\Closure::class . '->static' => ['pStatic', \T_FUNCTION],
1645
+ Expr\ArrowFunction::class . '->static' => ['pStatic', \T_FN],
1646
+ //Stmt\TraitUseAdaptation\Alias::class . '->newModifier' => 0, // TODO
1647
+ ];
1648
+
1649
+ // List of integer subnodes that are not modifiers:
1650
+ // Expr_Include->type
1651
+ // Stmt_GroupUse->type
1652
+ // Stmt_Use->type
1653
+ // UseItem->type
1654
+ }
1655
+ }