XmlAnalyzer.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053
  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 map<string, string>& templateSpecialization)
  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<string, string> it : templateSpecialization)
  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 map<string, string>& templateSpecialization)
  87. : node_(param)
  88. , templateSpecialization_(templateSpecialization)
  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, templateSpecialization_);
  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 ExtractProt(xml_node memberdef)
  168. {
  169. assert(IsMemberdef(memberdef));
  170. string result = memberdef.attribute("prot").value();
  171. assert(!result.empty());
  172. return result;
  173. }
  174. TypeAnalyzer ExtractType(xml_node memberdef, const map<string, string>& templateSpecialization)
  175. {
  176. assert(IsMemberdef(memberdef));
  177. xml_node type = memberdef.child("type");
  178. assert(type);
  179. // Doxygen bug workaround https://github.com/doxygen/doxygen/issues/7732
  180. // For user-defined conversion operator exract return type from function name
  181. if (RemoveRefs(type).empty() && ExtractKind(memberdef) == "function")
  182. {
  183. string functionName = ExtractName(memberdef);
  184. if (StartsWith(functionName, "operator "))
  185. return TypeAnalyzer(CutStart(functionName, "operator "));
  186. }
  187. return TypeAnalyzer(type, templateSpecialization);
  188. }
  189. vector<ParamAnalyzer> ExtractParams(xml_node memberdef, const map<string, string>& templateSpecialization)
  190. {
  191. assert(IsMemberdef(memberdef));
  192. assert(ExtractKind(memberdef) == "function");
  193. vector<ParamAnalyzer> result;
  194. for (xml_node param : memberdef.children("param"))
  195. result.push_back(ParamAnalyzer(param, templateSpecialization));
  196. return result;
  197. }
  198. string JoinParamsTypes(xml_node memberdef, const map<string, string>& templateSpecialization)
  199. {
  200. assert(IsMemberdef(memberdef));
  201. assert(ExtractKind(memberdef) == "function");
  202. string result;
  203. vector<ParamAnalyzer> params = ExtractParams(memberdef, templateSpecialization);
  204. for (const ParamAnalyzer& param : params)
  205. {
  206. if (!result.empty())
  207. result += ", ";
  208. result += param.GetType().ToString();
  209. }
  210. return result;
  211. }
  212. string JoinParamsNames(xml_node memberdef, bool skipContext)
  213. {
  214. assert(IsMemberdef(memberdef));
  215. assert(ExtractKind(memberdef) == "function");
  216. string result;
  217. vector<ParamAnalyzer> params = ExtractParams(memberdef);
  218. for (size_t i = 0; i < params.size(); i++)
  219. {
  220. ParamAnalyzer param = params[i];
  221. if (skipContext && i == 0)
  222. {
  223. assert(param.GetType().ToString() == "Context*");
  224. continue;
  225. }
  226. if (!result.empty())
  227. result += ", ";
  228. result += param.GetDeclname();
  229. }
  230. return result;
  231. }
  232. string ExtractID(xml_node node)
  233. {
  234. assert(IsMemberdef(node) || IsCompounddef(node));
  235. string result = node.attribute("id").value();
  236. assert(!result.empty());
  237. return result;
  238. }
  239. string ExtractKind(xml_node node)
  240. {
  241. assert(IsMemberdef(node) || IsCompounddef(node) || IsMember(node) || IsSectiondef(node));
  242. string result = node.attribute("kind").value();
  243. assert(!result.empty());
  244. return result;
  245. }
  246. string ExtractName(xml_node node)
  247. {
  248. assert(IsMemberdef(node) || IsEnumvalue(node));
  249. string result = node.child("name").child_value();
  250. assert(!result.empty());
  251. return result;
  252. }
  253. string ExtractLine(xml_node node)
  254. {
  255. assert(IsMemberdef(node) || IsCompounddef(node));
  256. string result = node.child("location").attribute("line").value();
  257. assert(!result.empty());
  258. return result;
  259. }
  260. string ExtractColumn(xml_node node)
  261. {
  262. assert(IsMemberdef(node) || IsCompounddef(node));
  263. string result = node.child("location").attribute("column").value();
  264. assert(!result.empty());
  265. return result;
  266. }
  267. static string DescriptionToString(xml_node description)
  268. {
  269. string result;
  270. for (xml_node para : description.children("para"))
  271. {
  272. result += RemoveRefs(para);
  273. result += " "; // To avoid gluing words from different paragraphs
  274. }
  275. return result;
  276. }
  277. string ExtractComment(xml_node node)
  278. {
  279. assert(IsMemberdef(node) || IsCompounddef(node));
  280. xml_node brief = node.child("briefdescription");
  281. assert(brief);
  282. xml_node detailed = node.child("detaileddescription");
  283. assert(detailed);
  284. return DescriptionToString(brief) + DescriptionToString(detailed);
  285. }
  286. static string HeaderFullPathToRelative(const string& fullPath)
  287. {
  288. size_t pos = fullPath.rfind("Source/Urho3D");
  289. assert(pos != string::npos);
  290. return ".." + fullPath.substr(pos + strlen("Source/Urho3D"));
  291. }
  292. string ExtractHeaderFile(xml_node node)
  293. {
  294. assert(IsMemberdef(node) || IsCompounddef(node));
  295. xml_node location = node.child("location");
  296. assert(!location.empty());
  297. string declfile = location.attribute("declfile").value();
  298. if (EndsWith(declfile, ".h"))
  299. return HeaderFullPathToRelative(declfile);
  300. string file = location.attribute("file").value();
  301. if (EndsWith(file, ".h"))
  302. return HeaderFullPathToRelative(file);
  303. return string();
  304. }
  305. bool IsTemplate(xml_node node)
  306. {
  307. assert(IsMemberdef(node) || IsCompounddef(node));
  308. return node.child("templateparamlist");
  309. }
  310. vector<string> ExtractTemplateParams(xml_node node)
  311. {
  312. assert(IsMemberdef(node) || IsCompounddef(node));
  313. vector<string> result;
  314. xml_node templateparamlist = node.child("templateparamlist");
  315. for (xml_node param : templateparamlist.children("param"))
  316. {
  317. string type = param.child_value("type");
  318. type = CutStart(type, "class ");
  319. type = CutStart(type, "typename ");
  320. result.push_back(type);
  321. }
  322. return result;
  323. }
  324. // ============================================================================
  325. EnumAnalyzer::EnumAnalyzer(xml_node memberdef)
  326. : memberdef_(memberdef)
  327. {
  328. assert(IsMemberdef(memberdef));
  329. assert(ExtractKind(memberdef) == "enum");
  330. }
  331. string EnumAnalyzer::GetBaseType() const
  332. {
  333. string result = memberdef_.child("type").child_value();
  334. if (result.empty())
  335. return "int";
  336. return result;
  337. }
  338. string EnumAnalyzer::GetLocation() const
  339. {
  340. string baseType = GetBaseType();
  341. if (baseType == "int")
  342. return "enum " + GetTypeName() + " | File: " + GetHeaderFile();
  343. return "enum " + GetTypeName() + " : " + baseType + " | File: " + GetHeaderFile();
  344. }
  345. vector<string> EnumAnalyzer::GetEnumerators() const
  346. {
  347. vector<string> result;
  348. for (xml_node enumvalue : memberdef_.children("enumvalue"))
  349. result.push_back(ExtractName(enumvalue));
  350. return result;
  351. }
  352. // ============================================================================
  353. GlobalVariableAnalyzer::GlobalVariableAnalyzer(xml_node memberdef)
  354. : memberdef_(memberdef)
  355. {
  356. assert(IsMemberdef(memberdef));
  357. assert(ExtractKind(memberdef) == "variable");
  358. }
  359. string GlobalVariableAnalyzer::GetLocation() const
  360. {
  361. string result = ExtractDefinition(memberdef_);
  362. result = RemoveFirst(result, "URHO3D_API ");
  363. assert(Contains(result, " Urho3D::"));
  364. result = ReplaceFirst(result, " Urho3D::", " ");
  365. if (IsStatic())
  366. result = "static " + result;
  367. result += " | File: " + GetHeaderFile();
  368. return result;
  369. }
  370. // ============================================================================
  371. ClassAnalyzer::ClassAnalyzer(xml_node compounddef)
  372. : compounddef_(compounddef)
  373. {
  374. assert(IsCompounddef(compounddef));
  375. }
  376. string ClassAnalyzer::GetClassName() const
  377. {
  378. string compoundname = ExtractCompoundname(compounddef_);
  379. assert(StartsWith(compoundname, "Urho3D::"));
  380. return CutStart(compoundname, "Urho3D::");
  381. }
  382. bool ClassAnalyzer::IsInternal() const
  383. {
  384. if (GetHeaderFile().empty()) // Defined in *.cpp
  385. return true;
  386. if (Contains(GetClassName(), "::")) // Defined inside another class
  387. return true;
  388. return false;
  389. }
  390. vector<xml_node> ClassAnalyzer::GetMemberdefs() const
  391. {
  392. vector<xml_node> result;
  393. xml_node listofallmembers = compounddef_.child("listofallmembers");
  394. assert(listofallmembers);
  395. for (xml_node member : listofallmembers.children("member"))
  396. {
  397. xml_attribute ambiguityscope = member.attribute("ambiguityscope");
  398. if (!ambiguityscope.empty()) // Overridden method from parent class
  399. continue;
  400. string refid = member.attribute("refid").value();
  401. assert(!refid.empty());
  402. auto it = SourceData::members_.find(refid);
  403. if (it == SourceData::members_.end())
  404. continue;
  405. xml_node memberdef = it->second;
  406. result.push_back(memberdef);
  407. }
  408. return result;
  409. }
  410. vector<ClassFunctionAnalyzer> ClassAnalyzer::GetFunctions() const
  411. {
  412. vector<ClassFunctionAnalyzer> result;
  413. vector<xml_node> memberdefs = GetMemberdefs();
  414. for (xml_node memberdef : memberdefs)
  415. {
  416. if (ExtractKind(memberdef) == "function")
  417. result.push_back(ClassFunctionAnalyzer(*this, memberdef));
  418. }
  419. return result;
  420. }
  421. vector<ClassVariableAnalyzer> ClassAnalyzer::GetVariables() const
  422. {
  423. vector<ClassVariableAnalyzer> result;
  424. vector<xml_node> memberdefs = GetMemberdefs();
  425. for (xml_node memberdef : memberdefs)
  426. {
  427. if (ExtractKind(memberdef) == "variable")
  428. result.push_back(ClassVariableAnalyzer(*this, memberdef));
  429. }
  430. return result;
  431. }
  432. bool ClassAnalyzer::ContainsFunction(const string& name) const
  433. {
  434. vector<ClassFunctionAnalyzer> functions = GetFunctions();
  435. for (const ClassFunctionAnalyzer& function : functions)
  436. {
  437. if (function.GetName() == name)
  438. return true;
  439. }
  440. return false;
  441. }
  442. ClassFunctionAnalyzer ClassAnalyzer::GetFunction(const string& name) const
  443. {
  444. vector<ClassFunctionAnalyzer> functions = GetFunctions();
  445. for (const ClassFunctionAnalyzer& function : functions)
  446. {
  447. if (function.GetName() == name)
  448. return function;
  449. }
  450. assert(false);
  451. return (ClassFunctionAnalyzer(*this, xml_node())); // xml_node can not be empty, so here we return incorrect value
  452. }
  453. int ClassAnalyzer::NumFunctions(const string& name) const
  454. {
  455. int result = 0;
  456. vector<ClassFunctionAnalyzer> functions = GetFunctions();
  457. for (const ClassFunctionAnalyzer& function : functions)
  458. {
  459. if (function.GetName() == name)
  460. result++;
  461. }
  462. return result;
  463. }
  464. bool ClassAnalyzer::IsAbstract() const
  465. {
  466. vector<ClassFunctionAnalyzer> functions = GetFunctions();
  467. for (const ClassFunctionAnalyzer& function : functions)
  468. {
  469. if (function.IsPureVirtual())
  470. {
  471. if (!IsRefCounted())
  472. return true;
  473. // Some pure virtual functions is implemented by URHO3D_OBJECT
  474. string name = function.GetName();
  475. if (name == "GetType" || name == "GetTypeInfo" || name == "GetTypeName")
  476. {
  477. if (ContainsFunction("URHO3D_OBJECT"))
  478. continue;
  479. }
  480. return true;
  481. }
  482. }
  483. return false;
  484. }
  485. bool ClassAnalyzer::AllFloats() const
  486. {
  487. if (Contains(GetComment(), "ALL_FLOATS")) // TODO: remove
  488. return true;
  489. vector<ClassVariableAnalyzer> variables = GetVariables();
  490. for (const ClassVariableAnalyzer& variable : variables)
  491. {
  492. if (variable.IsStatic())
  493. continue;
  494. string type = variable.GetType().ToString();
  495. if (type != "float" && type != "double")
  496. return false;
  497. }
  498. return true;
  499. }
  500. bool ClassAnalyzer::AllInts() const
  501. {
  502. if (Contains(GetComment(), "ALL_INTS")) // TODO: remove
  503. return true;
  504. vector<ClassVariableAnalyzer> variables = GetVariables();
  505. for (const ClassVariableAnalyzer& variable : variables)
  506. {
  507. if (variable.IsStatic())
  508. continue;
  509. string type = variable.GetType().ToString();
  510. if (type != "int" && type != "unsigned")
  511. return false;
  512. }
  513. return true;
  514. }
  515. bool ClassAnalyzer::IsPod() const
  516. {
  517. bool result = Contains(GetComment(), "IS_POD");
  518. if (AllFloats() || AllInts())
  519. result = true;
  520. return result;
  521. }
  522. shared_ptr<ClassAnalyzer> ClassAnalyzer::GetBaseClass() const
  523. {
  524. xml_node basecompoundref = compounddef_.child("basecompoundref");
  525. if (!basecompoundref)
  526. return shared_ptr<ClassAnalyzer>();
  527. string refid = basecompoundref.attribute("refid").value();
  528. assert(!refid.empty());
  529. auto it = SourceData::classesByID_.find(refid);
  530. if (it == SourceData::classesByID_.end())
  531. return shared_ptr<ClassAnalyzer>();
  532. xml_node compounddef = it->second;
  533. return make_shared<ClassAnalyzer>(compounddef);
  534. }
  535. vector<ClassAnalyzer> ClassAnalyzer::GetBaseClasses() const
  536. {
  537. vector<ClassAnalyzer> result;
  538. for (xml_node basecompoundref : compounddef_.children("basecompoundref"))
  539. {
  540. string refid = basecompoundref.attribute("refid").value();
  541. if (refid.empty()) // Type from ThirdParty lib
  542. continue;
  543. auto it = SourceData::classesByID_.find(refid);
  544. if (it == SourceData::classesByID_.end())
  545. continue;
  546. xml_node compounddef = it->second;
  547. result.push_back(ClassAnalyzer(compounddef));
  548. }
  549. return result;
  550. }
  551. static void RecursivelyGetBaseClasses(const ClassAnalyzer& analyzer, vector<ClassAnalyzer>& outResult)
  552. {
  553. for (const ClassAnalyzer& baseClass : analyzer.GetBaseClasses())
  554. {
  555. outResult.push_back(baseClass);
  556. RecursivelyGetBaseClasses(baseClass, outResult);
  557. }
  558. }
  559. vector<ClassAnalyzer> ClassAnalyzer::GetAllBaseClasses() const
  560. {
  561. vector<ClassAnalyzer> result;
  562. RecursivelyGetBaseClasses(*this, result);
  563. return result;
  564. }
  565. bool ClassAnalyzer::HasThisConstructor() const
  566. {
  567. vector<ClassFunctionAnalyzer> functions = GetFunctions();
  568. for (const ClassFunctionAnalyzer& function : functions)
  569. {
  570. if (function.IsThisConstructor())
  571. return true;
  572. }
  573. return false;
  574. }
  575. bool ClassAnalyzer::IsRefCounted() const
  576. {
  577. if (GetClassName() == "RefCounted")
  578. return true;
  579. vector<ClassAnalyzer> baseClasses = GetAllBaseClasses();
  580. for (const ClassAnalyzer& classAnalyzer : baseClasses)
  581. {
  582. if (classAnalyzer.GetClassName() == "RefCounted")
  583. return true;
  584. }
  585. return false;
  586. }
  587. // ============================================================================
  588. ClassFunctionAnalyzer::ClassFunctionAnalyzer(ClassAnalyzer classAnalyzer, xml_node memberdef)
  589. : classAnalyzer_(classAnalyzer)
  590. , memberdef_(memberdef)
  591. {
  592. assert(IsMemberdef(memberdef));
  593. assert(ExtractKind(memberdef) == "function");
  594. }
  595. string ClassFunctionAnalyzer::GetVirt() const
  596. {
  597. string result = memberdef_.attribute("virt").value();
  598. assert(!result.empty());
  599. return result;
  600. }
  601. string ClassFunctionAnalyzer::GetContainsClassName() const
  602. {
  603. string argsstring = ExtractArgsstring(memberdef_);
  604. assert(!argsstring.empty());
  605. string prototype = ExtractDefinition(memberdef_) + argsstring;
  606. smatch match;
  607. regex_match(prototype, match, regex(".*Urho3D::(.+?)::.*"));
  608. assert(match.size());
  609. string result = match[1].str();
  610. return result;
  611. }
  612. string GetFunctionLocation(xml_node memberdef)
  613. {
  614. assert(IsMemberdef(memberdef));
  615. assert(ExtractKind(memberdef) == "function");
  616. string argsstring = ExtractArgsstring(memberdef);
  617. assert(!argsstring.empty());
  618. string prototype = ExtractDefinition(memberdef) + argsstring;
  619. smatch match;
  620. regex_match(prototype, match, regex("([^(]*)Urho3D::(.+?)"));
  621. assert(match.size());
  622. string result = match[1].str() + match[2].str();
  623. if (IsExplicit(memberdef))
  624. result = "explicit " + result;
  625. result += " | File: " + ExtractHeaderFile(memberdef);
  626. if (IsTemplate(memberdef))
  627. {
  628. string t = "";
  629. xml_node templateparamlist = memberdef.child("templateparamlist");
  630. for (xml_node param : templateparamlist.children("param"))
  631. {
  632. if (t.length() > 0)
  633. t += ", ";
  634. xml_node type = param.child("type");
  635. assert(type);
  636. t += type.child_value();
  637. xml_node declname = param.child("declname");
  638. if (!declname.empty())
  639. t += " " + string(declname.child_value());
  640. }
  641. result = "template<" + t + "> " + result;
  642. }
  643. result = RemoveFirst(result, "URHO3D_API ");
  644. result = ReplaceAll(result, " **", "** ");
  645. result = ReplaceAll(result, " &&", "&& ");
  646. result = ReplaceAll(result, " *&", "*& ");
  647. result = ReplaceAll(result, " *", "* ");
  648. result = ReplaceAll(result, " &", "& ");
  649. result = ReplaceAll(result, " )", ")");
  650. result = ReplaceAll(result, "< ", "<");
  651. while (Contains(result, " >"))
  652. result = ReplaceAll(result, " >", ">");
  653. return result;
  654. }
  655. bool ClassFunctionAnalyzer::IsConst() const
  656. {
  657. string constAttr = memberdef_.attribute("const").value();
  658. assert(!constAttr.empty());
  659. return constAttr == "yes";
  660. }
  661. bool ClassFunctionAnalyzer::CanBeGetProperty() const
  662. {
  663. string returnType = GetReturnType().ToString();
  664. if (returnType == "void" || returnType.empty())
  665. return false;
  666. if (GetParams().size() != 0 && GetParams().size() != 1)
  667. return false;
  668. return true;
  669. }
  670. bool ClassFunctionAnalyzer::CanBeSetProperty() const
  671. {
  672. string returnType = GetReturnType().ToString();
  673. if (returnType != "void")
  674. return false;
  675. if (GetParams().size() != 1 && GetParams().size() != 2)
  676. return false;
  677. return true;
  678. }
  679. bool ClassFunctionAnalyzer::IsParentDestructor() const
  680. {
  681. string functionName = GetName();
  682. if (!StartsWith(functionName, "~"))
  683. return false;
  684. return !IsThisDestructor();
  685. }
  686. bool ClassFunctionAnalyzer::IsParentConstructor() const
  687. {
  688. if (IsThisConstructor())
  689. return false;
  690. string name = GetName();
  691. return ExtractDefinition(memberdef_) == "Urho3D::" + name + "::" + name;
  692. }
  693. shared_ptr<ClassFunctionAnalyzer> ClassFunctionAnalyzer::Reimplements() const
  694. {
  695. xml_node reimplements = memberdef_.child("reimplements");
  696. if (!reimplements)
  697. return shared_ptr<ClassFunctionAnalyzer>();
  698. string refid = reimplements.attribute("refid").value();
  699. assert(!refid.empty());
  700. auto it = SourceData::members_.find(refid);
  701. if (it == SourceData::members_.end())
  702. return shared_ptr<ClassFunctionAnalyzer>();
  703. xml_node memberdef = it->second;
  704. return make_shared<ClassFunctionAnalyzer>(classAnalyzer_, memberdef);
  705. }
  706. // ============================================================================
  707. ClassVariableAnalyzer::ClassVariableAnalyzer(ClassAnalyzer classAnalyzer, xml_node memberdef)
  708. : classAnalyzer_(classAnalyzer)
  709. , memberdef_(memberdef)
  710. {
  711. assert(IsMemberdef(memberdef));
  712. assert(ExtractKind(memberdef) == "variable");
  713. }
  714. string ClassVariableAnalyzer::GetLocation() const
  715. {
  716. string definition = ExtractDefinition(memberdef_);
  717. assert(!definition.empty());
  718. // Remove Urho3D::
  719. smatch match;
  720. regex_match(definition, match, regex("(.*)Urho3D::(.+)"));
  721. assert(match.size() == 3);
  722. string result = match[1].str() + match[2].str();
  723. result += " | File: " + GetHeaderFile();
  724. if (!classAnalyzer_.usingLocation_.empty())
  725. result = classAnalyzer_.usingLocation_ + " | " + result;
  726. return result;
  727. }
  728. // ============================================================================
  729. NamespaceAnalyzer::NamespaceAnalyzer(xml_node compounddef)
  730. : compounddef_(compounddef)
  731. {
  732. assert(IsCompounddef(compounddef));
  733. assert(ExtractKind(compounddef) == "namespace");
  734. }
  735. vector<EnumAnalyzer> NamespaceAnalyzer::GetEnums()
  736. {
  737. xml_node sectiondef = FindSectiondef(compounddef_, "enum");
  738. assert(sectiondef);
  739. vector<EnumAnalyzer> result;
  740. for (xml_node memberdef : sectiondef.children("memberdef"))
  741. {
  742. EnumAnalyzer analyzer(memberdef);
  743. result.push_back(analyzer);
  744. }
  745. return result;
  746. }
  747. vector<GlobalVariableAnalyzer> NamespaceAnalyzer::GetVariables()
  748. {
  749. xml_node sectiondef = FindSectiondef(compounddef_, "var");
  750. assert(sectiondef);
  751. vector<GlobalVariableAnalyzer> result;
  752. for (xml_node memberdef : sectiondef.children("memberdef"))
  753. result.push_back(GlobalVariableAnalyzer(memberdef));
  754. return result;
  755. }
  756. vector<GlobalFunctionAnalyzer> NamespaceAnalyzer::GetFunctions()
  757. {
  758. xml_node sectiondef = FindSectiondef(compounddef_, "func");
  759. assert(sectiondef);
  760. vector<GlobalFunctionAnalyzer> result;
  761. for (xml_node memberdef : sectiondef.children("memberdef"))
  762. result.push_back(GlobalFunctionAnalyzer(memberdef));
  763. return result;
  764. }
  765. // ============================================================================
  766. UsingAnalyzer::UsingAnalyzer(xml_node memberdef)
  767. : memberdef_(memberdef)
  768. {
  769. assert(IsMemberdef(memberdef));
  770. assert(ExtractKind(memberdef) == "typedef");
  771. }
  772. // ============================================================================
  773. GlobalFunctionAnalyzer::GlobalFunctionAnalyzer(xml_node memberdef, const map<string, string>& templateSpecialization)
  774. : memberdef_(memberdef)
  775. , templateSpecialization_(templateSpecialization)
  776. {
  777. assert(IsMemberdef(memberdef));
  778. assert(ExtractKind(memberdef) == "function");
  779. }
  780. // ============================================================================
  781. ClassStaticFunctionAnalyzer::ClassStaticFunctionAnalyzer(const ClassAnalyzer& classAnalyzer, xml_node memberdef)
  782. : classAnalyzer_(classAnalyzer)
  783. , memberdef_(memberdef)
  784. {
  785. assert(IsMemberdef(memberdef));
  786. assert(ExtractKind(memberdef) == "function");
  787. assert(IsStatic(memberdef));
  788. }