XmlAnalyzer.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098
  1. //
  2. // Copyright (c) 2008-2020 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Utils.h"
  23. #include "XmlAnalyzer.h"
  24. #include "XmlSourceData.h"
  25. #include <cassert>
  26. #include <regex>
  27. string RemoveRefs(xml_node node)
  28. {
  29. assert(node.name() == string("type") || node.name() == string("defval") || node.name() == string("para"));
  30. string result;
  31. for (xml_node part : node.children())
  32. {
  33. if (part.name() == string("ref"))
  34. result += part.child_value();
  35. else
  36. result += part.value();
  37. }
  38. return result;
  39. }
  40. TypeAnalyzer::TypeAnalyzer(xml_node type, const TemplateSpecialization& specialization)
  41. {
  42. assert(type.name() == string("type"));
  43. fullType_ = RemoveRefs(type);
  44. fullType_ = RemoveFirst(fullType_, "URHO3D_API ");
  45. fullType_ = CutStart(fullType_, "constexpr ");
  46. fullType_ = ReplaceAll(fullType_, " *", "*");
  47. fullType_ = ReplaceAll(fullType_, " &", "&");
  48. fullType_ = ReplaceAll(fullType_, "< ", "<");
  49. fullType_ = ReplaceAll(fullType_, " >", ">");
  50. for (pair<const string, string> it : specialization)
  51. {
  52. regex rgx("\\b" + it.first + "\\b");
  53. fullType_ = regex_replace(fullType_, rgx, it.second);
  54. }
  55. isConst_ = StartsWith(fullType_, "const ");
  56. name_ = CutStart(fullType_, "const ");
  57. isRvalueReference_ = EndsWith(name_, "&&");
  58. name_ = CutEnd(name_, "&&");
  59. isRefToPoiner_ = EndsWith(name_, "*&");
  60. name_ = CutEnd(name_, "*&");
  61. isDoublePointer_ = EndsWith(name_, "**");
  62. name_ = CutEnd(name_, "**");
  63. isPointer_ = EndsWith(name_, "*");
  64. name_ = CutEnd(name_, "*");
  65. isReference_ = EndsWith(name_, "&");
  66. name_ = CutEnd(name_, "&");
  67. smatch match;
  68. if (regex_match(name_, match, regex("(.+?)<(.+)>")))
  69. {
  70. templateParams_ = match[2].str();
  71. name_ = match[1].str();
  72. }
  73. }
  74. TypeAnalyzer::TypeAnalyzer(const string& typeName)
  75. {
  76. fullType_ = typeName;
  77. name_ = typeName;
  78. isConst_ = false;
  79. isPointer_ = false;
  80. isReference_ = false;
  81. isRvalueReference_ = false;
  82. isDoublePointer_ = false;
  83. isRefToPoiner_ = false;
  84. }
  85. // ============================================================================
  86. ParamAnalyzer::ParamAnalyzer(xml_node param, const TemplateSpecialization& specialization)
  87. : node_(param)
  88. , specialization_(specialization)
  89. {
  90. assert(node_.name() == string("param"));
  91. }
  92. string ParamAnalyzer::ToString() const
  93. {
  94. string type = GetType().ToString();
  95. assert(!type.empty());
  96. string name = GetDeclname();
  97. assert(!name.empty());
  98. return type + " " + name;
  99. }
  100. TypeAnalyzer ParamAnalyzer::GetType() const
  101. {
  102. xml_node type = node_.child("type");
  103. assert(type);
  104. return TypeAnalyzer(type, specialization_);
  105. }
  106. string ParamAnalyzer::GetDeclname() const
  107. {
  108. string result = node_.child("declname").child_value();
  109. assert(!result.empty());
  110. return result;
  111. }
  112. string ParamAnalyzer::GetDefval() const
  113. {
  114. xml_node defval = node_.child("defval");
  115. if (defval)
  116. return RemoveRefs(defval);
  117. return "";
  118. }
  119. // ============================================================================
  120. string ExtractCompoundname(xml_node compounddef)
  121. {
  122. assert(IsCompounddef(compounddef));
  123. string result = compounddef.child("compoundname").child_value();
  124. assert(!result.empty());
  125. return result;
  126. }
  127. xml_node FindSectiondef(xml_node compounddef, const string& kind)
  128. {
  129. assert(IsCompounddef(compounddef));
  130. assert(!kind.empty());
  131. for (xml_node sectiondef : compounddef.children("sectiondef"))
  132. {
  133. if (ExtractKind(sectiondef) == kind)
  134. return sectiondef;
  135. }
  136. return xml_node();
  137. }
  138. bool IsStatic(xml_node memberdef)
  139. {
  140. assert(IsMemberdef(memberdef));
  141. string staticAttr = memberdef.attribute("static").value();
  142. assert(!staticAttr.empty());
  143. return staticAttr == "yes";
  144. }
  145. bool IsExplicit(xml_node memberdef)
  146. {
  147. assert(IsMemberdef(memberdef));
  148. assert(ExtractKind(memberdef) == "function");
  149. string explicitAttr = memberdef.attribute("explicit").value();
  150. assert(!explicitAttr.empty());
  151. return explicitAttr == "yes";
  152. }
  153. string ExtractDefinition(xml_node memberdef)
  154. {
  155. assert(IsMemberdef(memberdef));
  156. string result = memberdef.child("definition").child_value();
  157. assert(!result.empty());
  158. return result;
  159. }
  160. string ExtractArgsstring(xml_node memberdef)
  161. {
  162. assert(IsMemberdef(memberdef));
  163. xml_node argsstring = memberdef.child("argsstring");
  164. assert(argsstring);
  165. return argsstring.child_value();
  166. }
  167. string ExtractCleanedFunctionArgsstring(xml_node memberdef)
  168. {
  169. assert(ExtractKind(memberdef) == "function");
  170. string argsstring = ExtractArgsstring(memberdef);
  171. assert(StartsWith(argsstring, "("));
  172. size_t endPos = argsstring.find_last_of(')');
  173. assert(endPos != string::npos);
  174. return argsstring.substr(1, endPos - 1);
  175. }
  176. string ExtractProt(xml_node memberdef)
  177. {
  178. assert(IsMemberdef(memberdef));
  179. string result = memberdef.attribute("prot").value();
  180. assert(!result.empty());
  181. return result;
  182. }
  183. TypeAnalyzer ExtractType(xml_node memberdef, const TemplateSpecialization& specialization)
  184. {
  185. assert(IsMemberdef(memberdef));
  186. xml_node type = memberdef.child("type");
  187. assert(type);
  188. // Doxygen bug workaround https://github.com/doxygen/doxygen/issues/7732
  189. // For user-defined conversion operator exract return type from function name
  190. if (RemoveRefs(type).empty() && ExtractKind(memberdef) == "function")
  191. {
  192. string functionName = ExtractName(memberdef);
  193. if (StartsWith(functionName, "operator "))
  194. return TypeAnalyzer(CutStart(functionName, "operator "));
  195. }
  196. return TypeAnalyzer(type, specialization);
  197. }
  198. vector<ParamAnalyzer> ExtractParams(xml_node memberdef, const TemplateSpecialization& specialization)
  199. {
  200. assert(IsMemberdef(memberdef));
  201. assert(ExtractKind(memberdef) == "function");
  202. vector<ParamAnalyzer> result;
  203. for (xml_node param : memberdef.children("param"))
  204. result.push_back(ParamAnalyzer(param, specialization));
  205. return result;
  206. }
  207. string JoinParamsTypes(xml_node memberdef, const TemplateSpecialization& specialization)
  208. {
  209. assert(IsMemberdef(memberdef));
  210. assert(ExtractKind(memberdef) == "function");
  211. string result;
  212. vector<ParamAnalyzer> params = ExtractParams(memberdef, specialization);
  213. for (const ParamAnalyzer& param : params)
  214. {
  215. if (!result.empty())
  216. result += ", ";
  217. result += param.GetType().ToString();
  218. }
  219. return result;
  220. }
  221. string JoinParamsNames(xml_node memberdef, bool skipContext)
  222. {
  223. assert(IsMemberdef(memberdef));
  224. assert(ExtractKind(memberdef) == "function");
  225. string result;
  226. vector<ParamAnalyzer> params = ExtractParams(memberdef);
  227. for (size_t i = 0; i < params.size(); i++)
  228. {
  229. ParamAnalyzer param = params[i];
  230. if (skipContext && i == 0)
  231. {
  232. assert(param.GetType().ToString() == "Context*");
  233. continue;
  234. }
  235. if (!result.empty())
  236. result += ", ";
  237. result += param.GetDeclname();
  238. }
  239. return result;
  240. }
  241. string ExtractID(xml_node node)
  242. {
  243. assert(IsMemberdef(node) || IsCompounddef(node));
  244. string result = node.attribute("id").value();
  245. assert(!result.empty());
  246. return result;
  247. }
  248. string ExtractKind(xml_node node)
  249. {
  250. assert(IsMemberdef(node) || IsCompounddef(node) || IsMember(node) || IsSectiondef(node));
  251. string result = node.attribute("kind").value();
  252. assert(!result.empty());
  253. return result;
  254. }
  255. string ExtractName(xml_node node)
  256. {
  257. assert(IsMemberdef(node) || IsEnumvalue(node));
  258. string result = node.child("name").child_value();
  259. assert(!result.empty());
  260. return result;
  261. }
  262. string ExtractLine(xml_node node)
  263. {
  264. assert(IsMemberdef(node) || IsCompounddef(node));
  265. string result = node.child("location").attribute("line").value();
  266. assert(!result.empty());
  267. return result;
  268. }
  269. string ExtractColumn(xml_node node)
  270. {
  271. assert(IsMemberdef(node) || IsCompounddef(node));
  272. string result = node.child("location").attribute("column").value();
  273. assert(!result.empty());
  274. return result;
  275. }
  276. static string DescriptionToString(xml_node description)
  277. {
  278. string result;
  279. for (xml_node para : description.children("para"))
  280. {
  281. result += RemoveRefs(para);
  282. result += " "; // To avoid gluing words from different paragraphs
  283. }
  284. return result;
  285. }
  286. string ExtractComment(xml_node node)
  287. {
  288. assert(IsMemberdef(node) || IsCompounddef(node));
  289. xml_node brief = node.child("briefdescription");
  290. assert(brief);
  291. xml_node detailed = node.child("detaileddescription");
  292. assert(detailed);
  293. return DescriptionToString(brief) + DescriptionToString(detailed);
  294. }
  295. static string HeaderFullPathToRelative(const string& fullPath)
  296. {
  297. size_t pos = fullPath.rfind("Source/Urho3D");
  298. assert(pos != string::npos);
  299. return ".." + fullPath.substr(pos + strlen("Source/Urho3D"));
  300. }
  301. string ExtractHeaderFile(xml_node node)
  302. {
  303. assert(IsMemberdef(node) || IsCompounddef(node));
  304. xml_node location = node.child("location");
  305. assert(!location.empty());
  306. string declfile = location.attribute("declfile").value();
  307. if (EndsWith(declfile, ".h"))
  308. return HeaderFullPathToRelative(declfile);
  309. string file = location.attribute("file").value();
  310. if (EndsWith(file, ".h"))
  311. return HeaderFullPathToRelative(file);
  312. return string();
  313. }
  314. bool IsTemplate(xml_node node)
  315. {
  316. assert(IsMemberdef(node) || IsCompounddef(node));
  317. return node.child("templateparamlist");
  318. }
  319. vector<string> ExtractTemplateParams(xml_node node)
  320. {
  321. assert(IsMemberdef(node) || IsCompounddef(node));
  322. vector<string> result;
  323. xml_node templateparamlist = node.child("templateparamlist");
  324. for (xml_node param : templateparamlist.children("param"))
  325. {
  326. string type = param.child_value("type");
  327. type = CutStart(type, "class ");
  328. type = CutStart(type, "typename ");
  329. result.push_back(type);
  330. }
  331. return result;
  332. }
  333. // ============================================================================
  334. EnumAnalyzer::EnumAnalyzer(xml_node memberdef)
  335. : memberdef_(memberdef)
  336. {
  337. assert(IsMemberdef(memberdef));
  338. assert(ExtractKind(memberdef) == "enum");
  339. }
  340. string EnumAnalyzer::GetBaseType() const
  341. {
  342. string result = memberdef_.child("type").child_value();
  343. if (result.empty())
  344. return "int";
  345. return result;
  346. }
  347. string EnumAnalyzer::GetLocation() const
  348. {
  349. string baseType = GetBaseType();
  350. if (baseType == "int")
  351. return "enum " + GetTypeName() + " | File: " + GetHeaderFile();
  352. return "enum " + GetTypeName() + " : " + baseType + " | File: " + GetHeaderFile();
  353. }
  354. vector<string> EnumAnalyzer::GetEnumerators() const
  355. {
  356. vector<string> result;
  357. for (xml_node enumvalue : memberdef_.children("enumvalue"))
  358. result.push_back(ExtractName(enumvalue));
  359. return result;
  360. }
  361. // ============================================================================
  362. GlobalVariableAnalyzer::GlobalVariableAnalyzer(xml_node memberdef)
  363. : memberdef_(memberdef)
  364. {
  365. assert(IsMemberdef(memberdef));
  366. assert(ExtractKind(memberdef) == "variable");
  367. }
  368. string GlobalVariableAnalyzer::GetLocation() const
  369. {
  370. string result = ExtractDefinition(memberdef_);
  371. result = RemoveFirst(result, "URHO3D_API ");
  372. assert(Contains(result, " Urho3D::"));
  373. result = ReplaceFirst(result, " Urho3D::", " ");
  374. if (IsStatic())
  375. result = "static " + result;
  376. result += " | File: " + GetHeaderFile();
  377. return result;
  378. }
  379. // ============================================================================
  380. ClassAnalyzer::ClassAnalyzer(xml_node compounddef, const TemplateSpecialization& specialization)
  381. : compounddef_(compounddef)
  382. , specialization_(specialization)
  383. {
  384. assert(IsCompounddef(compounddef));
  385. }
  386. string ClassAnalyzer::GetClassName() const
  387. {
  388. string compoundname = ExtractCompoundname(compounddef_);
  389. assert(StartsWith(compoundname, "Urho3D::"));
  390. return CutStart(compoundname, "Urho3D::");
  391. }
  392. bool ClassAnalyzer::IsInternal() const
  393. {
  394. if (GetHeaderFile().empty()) // Defined in *.cpp
  395. return true;
  396. if (Contains(GetClassName(), "::")) // Defined inside another class
  397. return true;
  398. return false;
  399. }
  400. vector<xml_node> ClassAnalyzer::GetMemberdefs() const
  401. {
  402. vector<xml_node> result;
  403. xml_node listofallmembers = compounddef_.child("listofallmembers");
  404. assert(listofallmembers);
  405. for (xml_node member : listofallmembers.children("member"))
  406. {
  407. xml_attribute ambiguityscope = member.attribute("ambiguityscope");
  408. if (!ambiguityscope.empty()) // Overridden method from parent class
  409. continue;
  410. string refid = member.attribute("refid").value();
  411. assert(!refid.empty());
  412. auto it = SourceData::members_.find(refid);
  413. if (it == SourceData::members_.end())
  414. continue;
  415. xml_node memberdef = it->second;
  416. result.push_back(memberdef);
  417. }
  418. return result;
  419. }
  420. vector<ClassFunctionAnalyzer> ClassAnalyzer::GetFunctions() const
  421. {
  422. vector<ClassFunctionAnalyzer> result;
  423. vector<xml_node> memberdefs = GetMemberdefs();
  424. for (xml_node memberdef : memberdefs)
  425. {
  426. if (ExtractKind(memberdef) == "function")
  427. result.push_back(ClassFunctionAnalyzer(*this, memberdef));
  428. }
  429. return result;
  430. }
  431. vector<ClassVariableAnalyzer> ClassAnalyzer::GetVariables() const
  432. {
  433. vector<ClassVariableAnalyzer> result;
  434. vector<xml_node> memberdefs = GetMemberdefs();
  435. for (xml_node memberdef : memberdefs)
  436. {
  437. if (ExtractKind(memberdef) == "variable")
  438. result.push_back(ClassVariableAnalyzer(*this, memberdef));
  439. }
  440. return result;
  441. }
  442. bool ClassAnalyzer::ContainsFunction(const string& name) const
  443. {
  444. vector<ClassFunctionAnalyzer> functions = GetFunctions();
  445. for (const ClassFunctionAnalyzer& function : functions)
  446. {
  447. if (function.GetName() == name)
  448. return true;
  449. }
  450. return false;
  451. }
  452. shared_ptr<ClassFunctionAnalyzer> ClassAnalyzer::GetFunction(const string& name) const
  453. {
  454. vector<ClassFunctionAnalyzer> functions = GetFunctions();
  455. for (const ClassFunctionAnalyzer& function : functions)
  456. {
  457. if (function.GetName() == name)
  458. return make_shared<ClassFunctionAnalyzer>(function);
  459. }
  460. return nullptr;
  461. }
  462. int ClassAnalyzer::NumFunctions(const string& name) const
  463. {
  464. int result = 0;
  465. vector<ClassFunctionAnalyzer> functions = GetFunctions();
  466. for (const ClassFunctionAnalyzer& function : functions)
  467. {
  468. if (function.GetName() == name)
  469. result++;
  470. }
  471. return result;
  472. }
  473. bool ClassAnalyzer::IsAbstract() const
  474. {
  475. vector<ClassFunctionAnalyzer> functions = GetFunctions();
  476. for (const ClassFunctionAnalyzer& function : functions)
  477. {
  478. if (function.IsPureVirtual())
  479. {
  480. if (!IsRefCounted())
  481. return true;
  482. // Some pure virtual functions is implemented by URHO3D_OBJECT
  483. string name = function.GetName();
  484. if (name == "GetType" || name == "GetTypeInfo" || name == "GetTypeName")
  485. {
  486. if (ContainsFunction("URHO3D_OBJECT"))
  487. continue;
  488. }
  489. return true;
  490. }
  491. }
  492. return false;
  493. }
  494. bool ClassAnalyzer::AllFloats() const
  495. {
  496. if (Contains(GetComment(), "ALL_FLOATS")) // TODO: remove
  497. return true;
  498. vector<ClassVariableAnalyzer> variables = GetVariables();
  499. for (const ClassVariableAnalyzer& variable : variables)
  500. {
  501. if (variable.IsStatic())
  502. continue;
  503. string type = variable.GetType().ToString();
  504. if (type != "float" && type != "double")
  505. return false;
  506. }
  507. return true;
  508. }
  509. bool ClassAnalyzer::AllInts() const
  510. {
  511. if (Contains(GetComment(), "ALL_INTS")) // TODO: remove
  512. return true;
  513. vector<ClassVariableAnalyzer> variables = GetVariables();
  514. for (const ClassVariableAnalyzer& variable : variables)
  515. {
  516. if (variable.IsStatic())
  517. continue;
  518. string type = variable.GetType().ToString();
  519. if (type != "int" && type != "unsigned")
  520. return false;
  521. }
  522. return true;
  523. }
  524. bool ClassAnalyzer::IsPod() const
  525. {
  526. bool result = Contains(GetComment(), "IS_POD");
  527. if (AllFloats() || AllInts())
  528. result = true;
  529. return result;
  530. }
  531. shared_ptr<ClassAnalyzer> ClassAnalyzer::GetBaseClass() const
  532. {
  533. xml_node basecompoundref = compounddef_.child("basecompoundref");
  534. if (!basecompoundref)
  535. return shared_ptr<ClassAnalyzer>();
  536. string refid = basecompoundref.attribute("refid").value();
  537. assert(!refid.empty());
  538. auto it = SourceData::classesByID_.find(refid);
  539. if (it == SourceData::classesByID_.end())
  540. return shared_ptr<ClassAnalyzer>();
  541. xml_node compounddef = it->second;
  542. return make_shared<ClassAnalyzer>(compounddef);
  543. }
  544. vector<ClassAnalyzer> ClassAnalyzer::GetBaseClasses() const
  545. {
  546. vector<ClassAnalyzer> result;
  547. for (xml_node basecompoundref : compounddef_.children("basecompoundref"))
  548. {
  549. string refid = basecompoundref.attribute("refid").value();
  550. if (refid.empty()) // Type from ThirdParty lib
  551. continue;
  552. auto it = SourceData::classesByID_.find(refid);
  553. if (it == SourceData::classesByID_.end())
  554. continue;
  555. xml_node compounddef = it->second;
  556. result.push_back(ClassAnalyzer(compounddef));
  557. }
  558. return result;
  559. }
  560. static void RecursivelyGetBaseClasses(const ClassAnalyzer& analyzer, vector<ClassAnalyzer>& outResult)
  561. {
  562. for (const ClassAnalyzer& baseClass : analyzer.GetBaseClasses())
  563. {
  564. outResult.push_back(baseClass);
  565. RecursivelyGetBaseClasses(baseClass, outResult);
  566. }
  567. }
  568. vector<ClassAnalyzer> ClassAnalyzer::GetAllBaseClasses() const
  569. {
  570. vector<ClassAnalyzer> result;
  571. RecursivelyGetBaseClasses(*this, result);
  572. return result;
  573. }
  574. bool ClassAnalyzer::HasThisConstructor() const
  575. {
  576. vector<ClassFunctionAnalyzer> functions = GetFunctions();
  577. for (const ClassFunctionAnalyzer& function : functions)
  578. {
  579. if (function.IsThisConstructor())
  580. return true;
  581. }
  582. return false;
  583. }
  584. bool ClassAnalyzer::IsRefCounted() const
  585. {
  586. if (GetClassName() == "RefCounted")
  587. return true;
  588. vector<ClassAnalyzer> baseClasses = GetAllBaseClasses();
  589. for (const ClassAnalyzer& classAnalyzer : baseClasses)
  590. {
  591. if (classAnalyzer.GetClassName() == "RefCounted")
  592. return true;
  593. }
  594. return false;
  595. }
  596. shared_ptr<ClassFunctionAnalyzer> ClassAnalyzer::GetDefinedThisDefaultConstructor() const
  597. {
  598. vector<ClassFunctionAnalyzer> functions = GetFunctions();
  599. for (const ClassFunctionAnalyzer& function : functions)
  600. {
  601. if (function.IsThisDefaultConstructor())
  602. return make_shared<ClassFunctionAnalyzer>(function);
  603. }
  604. return nullptr;
  605. }
  606. vector<ClassFunctionAnalyzer> ClassAnalyzer::GetThisNonDefaultConstructors() const
  607. {
  608. vector<ClassFunctionAnalyzer> result;
  609. vector<ClassFunctionAnalyzer> functions = GetFunctions();
  610. for (const ClassFunctionAnalyzer& function : functions)
  611. {
  612. if (function.IsThisNonDefaultConstructor())
  613. result.push_back(function);
  614. }
  615. return result;
  616. }
  617. // ============================================================================
  618. FunctionAnalyzer::FunctionAnalyzer(xml_node memberdef, const TemplateSpecialization& specialization)
  619. : memberdef_(memberdef)
  620. , specialization_(specialization)
  621. {
  622. assert(IsMemberdef(memberdef));
  623. assert(ExtractKind(memberdef) == "function");
  624. }
  625. // ============================================================================
  626. ClassFunctionAnalyzer::ClassFunctionAnalyzer(const ClassAnalyzer& classAnalyzer, xml_node memberdef, const TemplateSpecialization& specialization)
  627. : FunctionAnalyzer(memberdef, specialization)
  628. , classAnalyzer_(classAnalyzer)
  629. {
  630. // Append template specialization from class
  631. specialization_.insert(classAnalyzer.GetSpecialization().begin(), classAnalyzer.GetSpecialization().end());
  632. }
  633. string ClassFunctionAnalyzer::GetVirt() const
  634. {
  635. string result = memberdef_.attribute("virt").value();
  636. assert(!result.empty());
  637. return result;
  638. }
  639. string ClassFunctionAnalyzer::GetContainsClassName() const
  640. {
  641. string argsstring = ExtractArgsstring(memberdef_);
  642. assert(!argsstring.empty());
  643. string prototype = ExtractDefinition(memberdef_) + argsstring;
  644. smatch match;
  645. regex_match(prototype, match, regex(".*Urho3D::(.+?)::.*"));
  646. assert(match.size());
  647. string result = match[1].str();
  648. return result;
  649. }
  650. string GetFunctionLocation(xml_node memberdef)
  651. {
  652. assert(IsMemberdef(memberdef));
  653. assert(ExtractKind(memberdef) == "function");
  654. string argsstring = ExtractArgsstring(memberdef);
  655. assert(!argsstring.empty());
  656. string prototype = ExtractDefinition(memberdef) + argsstring;
  657. smatch match;
  658. regex_match(prototype, match, regex("([^(]*)Urho3D::(.+?)"));
  659. assert(match.size());
  660. string result = match[1].str() + match[2].str();
  661. if (IsExplicit(memberdef))
  662. result = "explicit " + result;
  663. result += " | File: " + ExtractHeaderFile(memberdef);
  664. if (IsTemplate(memberdef))
  665. {
  666. string t = "";
  667. xml_node templateparamlist = memberdef.child("templateparamlist");
  668. for (xml_node param : templateparamlist.children("param"))
  669. {
  670. if (t.length() > 0)
  671. t += ", ";
  672. xml_node type = param.child("type");
  673. assert(type);
  674. t += type.child_value();
  675. xml_node declname = param.child("declname");
  676. if (!declname.empty())
  677. t += " " + string(declname.child_value());
  678. }
  679. result = "template<" + t + "> " + result;
  680. }
  681. result = RemoveFirst(result, "URHO3D_API ");
  682. result = ReplaceAll(result, " **", "** ");
  683. result = ReplaceAll(result, " &&", "&& ");
  684. result = ReplaceAll(result, " *&", "*& ");
  685. result = ReplaceAll(result, " *", "* ");
  686. result = ReplaceAll(result, " &", "& ");
  687. result = ReplaceAll(result, " )", ")");
  688. result = ReplaceAll(result, "< ", "<");
  689. while (Contains(result, " >"))
  690. result = ReplaceAll(result, " >", ">");
  691. return result;
  692. }
  693. bool ClassFunctionAnalyzer::IsConst() const
  694. {
  695. string constAttr = memberdef_.attribute("const").value();
  696. assert(!constAttr.empty());
  697. return constAttr == "yes";
  698. }
  699. bool ClassFunctionAnalyzer::CanBeGetProperty() const
  700. {
  701. string returnType = GetReturnType().ToString();
  702. if (returnType == "void" || returnType.empty())
  703. return false;
  704. if (GetParams().size() != 0 && GetParams().size() != 1)
  705. return false;
  706. return true;
  707. }
  708. bool ClassFunctionAnalyzer::CanBeSetProperty() const
  709. {
  710. string returnType = GetReturnType().ToString();
  711. if (returnType != "void")
  712. return false;
  713. if (GetParams().size() != 1 && GetParams().size() != 2)
  714. return false;
  715. return true;
  716. }
  717. bool ClassFunctionAnalyzer::IsParentDestructor() const
  718. {
  719. string functionName = GetName();
  720. if (!StartsWith(functionName, "~"))
  721. return false;
  722. return !IsThisDestructor();
  723. }
  724. bool ClassFunctionAnalyzer::IsParentConstructor() const
  725. {
  726. if (IsThisConstructor())
  727. return false;
  728. string name = GetName();
  729. return ExtractDefinition(memberdef_) == "Urho3D::" + name + "::" + name;
  730. }
  731. shared_ptr<ClassFunctionAnalyzer> ClassFunctionAnalyzer::Reimplements() const
  732. {
  733. xml_node reimplements = memberdef_.child("reimplements");
  734. if (!reimplements)
  735. return shared_ptr<ClassFunctionAnalyzer>();
  736. string refid = reimplements.attribute("refid").value();
  737. assert(!refid.empty());
  738. auto it = SourceData::members_.find(refid);
  739. if (it == SourceData::members_.end())
  740. return shared_ptr<ClassFunctionAnalyzer>();
  741. xml_node memberdef = it->second;
  742. return make_shared<ClassFunctionAnalyzer>(classAnalyzer_, memberdef);
  743. }
  744. // ============================================================================
  745. ClassVariableAnalyzer::ClassVariableAnalyzer(ClassAnalyzer classAnalyzer, xml_node memberdef)
  746. : classAnalyzer_(classAnalyzer)
  747. , memberdef_(memberdef)
  748. {
  749. assert(IsMemberdef(memberdef));
  750. assert(ExtractKind(memberdef) == "variable");
  751. }
  752. string ClassVariableAnalyzer::GetLocation() const
  753. {
  754. string definition = ExtractDefinition(memberdef_);
  755. assert(!definition.empty());
  756. // Remove Urho3D::
  757. smatch match;
  758. regex_match(definition, match, regex("(.*)Urho3D::(.+)"));
  759. assert(match.size() == 3);
  760. string result = match[1].str() + match[2].str();
  761. result += " | File: " + GetHeaderFile();
  762. if (!classAnalyzer_.usingLocation_.empty())
  763. result = classAnalyzer_.usingLocation_ + " | " + result;
  764. return result;
  765. }
  766. // ============================================================================
  767. NamespaceAnalyzer::NamespaceAnalyzer(xml_node compounddef)
  768. : compounddef_(compounddef)
  769. {
  770. assert(IsCompounddef(compounddef));
  771. assert(ExtractKind(compounddef) == "namespace");
  772. }
  773. vector<EnumAnalyzer> NamespaceAnalyzer::GetEnums()
  774. {
  775. xml_node sectiondef = FindSectiondef(compounddef_, "enum");
  776. assert(sectiondef);
  777. vector<EnumAnalyzer> result;
  778. for (xml_node memberdef : sectiondef.children("memberdef"))
  779. {
  780. EnumAnalyzer analyzer(memberdef);
  781. result.push_back(analyzer);
  782. }
  783. return result;
  784. }
  785. vector<GlobalVariableAnalyzer> NamespaceAnalyzer::GetVariables()
  786. {
  787. xml_node sectiondef = FindSectiondef(compounddef_, "var");
  788. assert(sectiondef);
  789. vector<GlobalVariableAnalyzer> result;
  790. for (xml_node memberdef : sectiondef.children("memberdef"))
  791. result.push_back(GlobalVariableAnalyzer(memberdef));
  792. return result;
  793. }
  794. vector<GlobalFunctionAnalyzer> NamespaceAnalyzer::GetFunctions()
  795. {
  796. xml_node sectiondef = FindSectiondef(compounddef_, "func");
  797. assert(sectiondef);
  798. vector<GlobalFunctionAnalyzer> result;
  799. for (xml_node memberdef : sectiondef.children("memberdef"))
  800. result.push_back(GlobalFunctionAnalyzer(memberdef));
  801. return result;
  802. }
  803. // ============================================================================
  804. UsingAnalyzer::UsingAnalyzer(xml_node memberdef)
  805. : memberdef_(memberdef)
  806. {
  807. assert(IsMemberdef(memberdef));
  808. assert(ExtractKind(memberdef) == "typedef");
  809. }
  810. // ============================================================================
  811. GlobalFunctionAnalyzer::GlobalFunctionAnalyzer(xml_node memberdef, const TemplateSpecialization& specialization)
  812. : FunctionAnalyzer(memberdef, specialization)
  813. {
  814. }
  815. // ============================================================================
  816. ClassStaticFunctionAnalyzer::ClassStaticFunctionAnalyzer(const ClassAnalyzer& classAnalyzer, xml_node memberdef, const TemplateSpecialization& specialization)
  817. : FunctionAnalyzer(memberdef, specialization)
  818. , classAnalyzer_(classAnalyzer)
  819. {
  820. assert(IsStatic(memberdef));
  821. }