XmlAnalyzer.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455
  1. //
  2. // Copyright (c) 2008-2022 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. using namespace std;
  28. using namespace pugi;
  29. extern string _sourceDir;
  30. string RemoveRefs(xml_node node)
  31. {
  32. assert(node.name() == string("type") || node.name() == string("defval") || node.name() == string("para"));
  33. string result;
  34. for (xml_node part : node.children())
  35. {
  36. if (part.name() == string("ref"))
  37. result += part.child_value();
  38. else
  39. result += part.value();
  40. }
  41. return result;
  42. }
  43. TypeAnalyzer::TypeAnalyzer(xml_node type, const TemplateSpecialization& specialization)
  44. {
  45. assert(type.name() == string("type"));
  46. fullType_ = RemoveRefs(type);
  47. fullType_ = RemoveFirst(fullType_, "URHO3D_API ");
  48. fullType_ = RemoveFirst(fullType_, " URHO3D_API");
  49. fullType_ = CutStart(fullType_, "volatile ");
  50. fullType_ = ReplaceAll(fullType_, " *", "*");
  51. fullType_ = ReplaceAll(fullType_, " &", "&");
  52. fullType_ = ReplaceAll(fullType_, "< ", "<");
  53. fullType_ = ReplaceAll(fullType_, " >", ">");
  54. for (pair<const string, string> it : specialization)
  55. {
  56. regex rgx("\\b" + it.first + "\\b");
  57. fullType_ = regex_replace(fullType_, rgx, it.second);
  58. }
  59. if (StartsWith(fullType_, "constexpr "))
  60. {
  61. isConstexpr_ = true;
  62. isConst_ = false;
  63. fullType_ = CutStart(fullType_, "constexpr ");
  64. name_ = fullType_;
  65. }
  66. else if (StartsWith(fullType_, "const "))
  67. {
  68. isConst_ = true;
  69. isConstexpr_ = false;
  70. name_ = CutStart(fullType_, "const ");
  71. }
  72. else
  73. {
  74. isConst_ = false;
  75. isConstexpr_ = false;
  76. name_ = fullType_;
  77. }
  78. isRvalueReference_ = EndsWith(name_, "&&");
  79. name_ = CutEnd(name_, "&&");
  80. isRefToPoiner_ = EndsWith(name_, "*&");
  81. name_ = CutEnd(name_, "*&");
  82. isDoublePointer_ = EndsWith(name_, "**");
  83. name_ = CutEnd(name_, "**");
  84. isPointer_ = EndsWith(name_, "*");
  85. name_ = CutEnd(name_, "*");
  86. isReference_ = EndsWith(name_, "&");
  87. name_ = CutEnd(name_, "&");
  88. smatch match;
  89. if (regex_match(name_, match, regex("(.+?)<(.+)>")))
  90. {
  91. templateParams_ = match[2].str();
  92. name_ = match[1].str();
  93. }
  94. }
  95. TypeAnalyzer::TypeAnalyzer(const string& typeName)
  96. {
  97. fullType_ = typeName;
  98. name_ = typeName;
  99. isConst_ = false;
  100. isConstexpr_ = false;
  101. isPointer_ = false;
  102. isReference_ = false;
  103. isRvalueReference_ = false;
  104. isDoublePointer_ = false;
  105. isRefToPoiner_ = false;
  106. }
  107. // ============================================================================
  108. ParamAnalyzer::ParamAnalyzer(xml_node param, const TemplateSpecialization& specialization)
  109. : node_(param)
  110. , specialization_(specialization)
  111. {
  112. assert(node_.name() == string("param"));
  113. }
  114. string ParamAnalyzer::ToString() const
  115. {
  116. string type = GetType().ToString();
  117. assert(!type.empty());
  118. string name = GetDeclname();
  119. assert(!name.empty());
  120. return type + " " + name;
  121. }
  122. TypeAnalyzer ParamAnalyzer::GetType() const
  123. {
  124. xml_node type = node_.child("type");
  125. assert(type);
  126. return TypeAnalyzer(type, specialization_);
  127. }
  128. string ParamAnalyzer::GetDeclname() const
  129. {
  130. string result = node_.child("declname").child_value();
  131. //assert(!result.empty()); TODO
  132. return result;
  133. }
  134. string ParamAnalyzer::GetDefval() const
  135. {
  136. xml_node defval = node_.child("defval");
  137. if (defval)
  138. return RemoveRefs(defval);
  139. return "";
  140. }
  141. // ============================================================================
  142. string ExtractCompoundname(xml_node compounddef)
  143. {
  144. assert(IsCompounddef(compounddef));
  145. string result = compounddef.child("compoundname").child_value();
  146. assert(!result.empty());
  147. return result;
  148. }
  149. xml_node FindSectiondef(xml_node compounddef, const string& kind)
  150. {
  151. assert(IsCompounddef(compounddef));
  152. assert(!kind.empty());
  153. for (xml_node sectiondef : compounddef.children("sectiondef"))
  154. {
  155. if (ExtractKind(sectiondef) == kind)
  156. return sectiondef;
  157. }
  158. return xml_node();
  159. }
  160. bool IsStatic(xml_node memberdef)
  161. {
  162. assert(IsMemberdef(memberdef));
  163. string staticAttr = memberdef.attribute("static").value();
  164. assert(!staticAttr.empty());
  165. return staticAttr == "yes";
  166. }
  167. bool IsExplicit(xml_node memberdef)
  168. {
  169. assert(IsMemberdef(memberdef));
  170. assert(ExtractKind(memberdef) == "function");
  171. string explicitAttr = memberdef.attribute("explicit").value();
  172. assert(!explicitAttr.empty());
  173. return explicitAttr == "yes";
  174. }
  175. string ExtractDefinition(xml_node memberdef)
  176. {
  177. assert(IsMemberdef(memberdef));
  178. string result = memberdef.child("definition").child_value();
  179. assert(!result.empty());
  180. return result;
  181. }
  182. static string BeautifyDefinition(const string& definition)
  183. {
  184. string result = definition;
  185. result = ReplaceAll(result, " **", "** ");
  186. result = ReplaceAll(result, " &&", "&& ");
  187. result = ReplaceAll(result, " *&", "*& ");
  188. result = ReplaceAll(result, " *", "* ");
  189. result = ReplaceAll(result, " &", "& ");
  190. result = ReplaceAll(result, "=", " = ");
  191. result = ReplaceAll(result, " = = ", "==");
  192. result = ReplaceAll(result, "! = ", "!=");
  193. result = ReplaceAll(result, "+ = ", "+=");
  194. result = ReplaceAll(result, "- = ", "-=");
  195. result = ReplaceAll(result, "* = ", "*=");
  196. result = ReplaceAll(result, "/ = ", "/=");
  197. result = ReplaceAll(result, "operator = ", "operator=");
  198. result = ReplaceAll(result, "operator", "operator ");
  199. while (Contains(result, " "))
  200. result = ReplaceAll(result, " ", " ");
  201. result = ReplaceAll(result, " )", ")");
  202. result = ReplaceAll(result, "< ", "<");
  203. result = ReplaceAll(result, " >", ">");
  204. result = ReplaceAll(result, "template<", "template <");
  205. return result;
  206. }
  207. string ExtractArgsstring(xml_node memberdef)
  208. {
  209. assert(IsMemberdef(memberdef));
  210. xml_node argsstring = memberdef.child("argsstring");
  211. assert(argsstring);
  212. return argsstring.child_value();
  213. }
  214. string ExtractCleanedFunctionArgsstring(xml_node memberdef)
  215. {
  216. assert(ExtractKind(memberdef) == "function");
  217. string argsstring = ExtractArgsstring(memberdef);
  218. assert(StartsWith(argsstring, "("));
  219. size_t endPos = argsstring.find_last_of(')');
  220. assert(endPos != string::npos);
  221. return argsstring.substr(1, endPos - 1);
  222. }
  223. string ExtractProt(xml_node memberdef)
  224. {
  225. assert(IsMemberdef(memberdef));
  226. string result = memberdef.attribute("prot").value();
  227. assert(!result.empty());
  228. return result;
  229. }
  230. TypeAnalyzer ExtractType(xml_node memberdef, const TemplateSpecialization& specialization)
  231. {
  232. assert(IsMemberdef(memberdef));
  233. xml_node type = memberdef.child("type");
  234. assert(type);
  235. // Doxygen bug workaround https://github.com/doxygen/doxygen/issues/7732
  236. // For user-defined conversion operator exract return type from function name
  237. if (RemoveRefs(type).empty() && ExtractKind(memberdef) == "function")
  238. {
  239. string functionName = ExtractName(memberdef);
  240. if (StartsWith(functionName, "operator "))
  241. return TypeAnalyzer(CutStart(functionName, "operator "));
  242. }
  243. return TypeAnalyzer(type, specialization);
  244. }
  245. vector<ParamAnalyzer> ExtractParams(xml_node memberdef, const TemplateSpecialization& specialization)
  246. {
  247. assert(IsMemberdef(memberdef));
  248. assert(ExtractKind(memberdef) == "function");
  249. vector<ParamAnalyzer> result;
  250. for (xml_node param : memberdef.children("param"))
  251. result.push_back(ParamAnalyzer(param, specialization));
  252. return result;
  253. }
  254. string JoinParamsTypes(xml_node memberdef, const TemplateSpecialization& specialization)
  255. {
  256. assert(IsMemberdef(memberdef));
  257. assert(ExtractKind(memberdef) == "function");
  258. string result;
  259. vector<ParamAnalyzer> params = ExtractParams(memberdef, specialization);
  260. for (const ParamAnalyzer& param : params)
  261. {
  262. if (!result.empty())
  263. result += ", ";
  264. result += param.GetType().ToString();
  265. }
  266. return result;
  267. }
  268. string JoinParamsNames(xml_node memberdef, bool skipContext)
  269. {
  270. assert(IsMemberdef(memberdef));
  271. assert(ExtractKind(memberdef) == "function");
  272. string result;
  273. vector<ParamAnalyzer> params = ExtractParams(memberdef);
  274. for (size_t i = 0; i < params.size(); i++)
  275. {
  276. ParamAnalyzer param = params[i];
  277. if (skipContext && i == 0)
  278. {
  279. assert(param.GetType().ToString() == "Context*");
  280. continue;
  281. }
  282. if (!result.empty())
  283. result += ", ";
  284. result += param.GetDeclname();
  285. }
  286. return result;
  287. }
  288. string ExtractID(xml_node node)
  289. {
  290. assert(IsMemberdef(node) || IsCompounddef(node));
  291. string result = node.attribute("id").value();
  292. assert(!result.empty());
  293. return result;
  294. }
  295. string ExtractKind(xml_node node)
  296. {
  297. assert(IsMemberdef(node) || IsCompounddef(node) || IsMember(node) || IsSectiondef(node));
  298. string result = node.attribute("kind").value();
  299. assert(!result.empty());
  300. return result;
  301. }
  302. string ExtractName(xml_node node)
  303. {
  304. assert(IsMemberdef(node) || IsEnumvalue(node));
  305. string result = node.child("name").child_value();
  306. assert(!result.empty());
  307. return result;
  308. }
  309. string ExtractLine(xml_node node)
  310. {
  311. assert(IsMemberdef(node) || IsCompounddef(node));
  312. string result = node.child("location").attribute("line").value();
  313. assert(!result.empty());
  314. return result;
  315. }
  316. string ExtractColumn(xml_node node)
  317. {
  318. assert(IsMemberdef(node) || IsCompounddef(node));
  319. string result = node.child("location").attribute("column").value();
  320. assert(!result.empty());
  321. return result;
  322. }
  323. static string DescriptionToString(xml_node description)
  324. {
  325. string result;
  326. for (xml_node para : description.children("para"))
  327. {
  328. result += RemoveRefs(para);
  329. result += " "; // To avoid gluing words from different paragraphs
  330. }
  331. return result;
  332. }
  333. string ExtractComment(xml_node node)
  334. {
  335. assert(IsMemberdef(node) || IsCompounddef(node));
  336. xml_node brief = node.child("briefdescription");
  337. assert(brief);
  338. xml_node detailed = node.child("detaileddescription");
  339. assert(detailed);
  340. return DescriptionToString(brief) + DescriptionToString(detailed);
  341. }
  342. static string HeaderFullPathToRelative(const string& fullPath)
  343. {
  344. assert(StartsWith(fullPath, _sourceDir + "/Source/Urho3D"));
  345. return ".." + CutStart(fullPath, _sourceDir + "/Source/Urho3D");
  346. }
  347. string ExtractHeaderFile(xml_node node)
  348. {
  349. assert(IsMemberdef(node) || IsCompounddef(node));
  350. xml_node location = node.child("location");
  351. assert(!location.empty());
  352. string declfile = location.attribute("declfile").value();
  353. if (EndsWith(declfile, ".h"))
  354. return HeaderFullPathToRelative(declfile);
  355. string file = location.attribute("file").value();
  356. if (EndsWith(file, ".h"))
  357. return HeaderFullPathToRelative(file);
  358. return string();
  359. }
  360. bool IsTemplate(xml_node node)
  361. {
  362. assert(IsMemberdef(node) || IsCompounddef(node));
  363. return node.child("templateparamlist");
  364. }
  365. vector<string> ExtractTemplateParams(xml_node node)
  366. {
  367. assert(IsMemberdef(node) || IsCompounddef(node));
  368. vector<string> result;
  369. xml_node templateparamlist = node.child("templateparamlist");
  370. for (xml_node param : templateparamlist.children("param"))
  371. {
  372. string type = param.child_value("type");
  373. type = CutStart(type, "class ");
  374. type = CutStart(type, "typename ");
  375. result.push_back(type);
  376. }
  377. return result;
  378. }
  379. // ============================================================================
  380. EnumAnalyzer::EnumAnalyzer(xml_node memberdef)
  381. : memberdef_(memberdef)
  382. {
  383. assert(IsMemberdef(memberdef));
  384. assert(ExtractKind(memberdef) == "enum");
  385. }
  386. string EnumAnalyzer::GetBaseType() const
  387. {
  388. string result = memberdef_.child("type").child_value();
  389. if (result.empty())
  390. return "int";
  391. return result;
  392. }
  393. string EnumAnalyzer::GetLocation() const
  394. {
  395. string baseType = GetBaseType();
  396. if (baseType == "int")
  397. return "enum " + GetTypeName() + " | File: " + GetHeaderFile();
  398. return "enum " + GetTypeName() + " : " + baseType + " | File: " + GetHeaderFile();
  399. }
  400. vector<string> EnumAnalyzer::GetEnumerators() const
  401. {
  402. vector<string> result;
  403. for (xml_node enumvalue : memberdef_.children("enumvalue"))
  404. result.push_back(ExtractName(enumvalue));
  405. return result;
  406. }
  407. // ============================================================================
  408. GlobalVariableAnalyzer::GlobalVariableAnalyzer(xml_node memberdef)
  409. : memberdef_(memberdef)
  410. {
  411. assert(IsMemberdef(memberdef));
  412. assert(ExtractKind(memberdef) == "variable");
  413. }
  414. // ============================================================================
  415. ClassAnalyzer::ClassAnalyzer(xml_node compounddef, const TemplateSpecialization& specialization)
  416. : compounddef_(compounddef)
  417. , specialization_(specialization)
  418. {
  419. assert(IsCompounddef(compounddef));
  420. }
  421. string ClassAnalyzer::GetClassName() const
  422. {
  423. string compoundname = ExtractCompoundname(compounddef_);
  424. assert(StartsWith(compoundname, "Urho3D::"));
  425. return CutStart(compoundname, "Urho3D::");
  426. }
  427. string ClassAnalyzer::GetDirName() const
  428. {
  429. string str = CutStart(GetHeaderFile(), "../");
  430. size_t pos = str.find('/');
  431. assert(pos != string::npos);
  432. return str.substr(0, pos);
  433. }
  434. bool ClassAnalyzer::IsInternal() const
  435. {
  436. if (GetHeaderFile().empty()) // Defined in *.cpp
  437. return true;
  438. if (Contains(GetClassName(), "::")) // Defined inside another class
  439. return true;
  440. return false;
  441. }
  442. vector<xml_node> ClassAnalyzer::GetMemberdefs() const
  443. {
  444. vector<xml_node> result;
  445. xml_node listofallmembers = compounddef_.child("listofallmembers");
  446. assert(listofallmembers);
  447. for (xml_node member : listofallmembers.children("member"))
  448. {
  449. xml_attribute ambiguityscope = member.attribute("ambiguityscope");
  450. if (!ambiguityscope.empty())
  451. continue;
  452. string refid = member.attribute("refid").value();
  453. assert(!refid.empty());
  454. auto it = SourceData::members_.find(refid);
  455. if (it == SourceData::members_.end())
  456. continue;
  457. xml_node memberdef = it->second;
  458. result.push_back(memberdef);
  459. }
  460. return result;
  461. }
  462. vector<string> ClassAnalyzer::GetAllPublicMembersRefids() const
  463. {
  464. vector<string> result;
  465. xml_node listofallmembers = compounddef_.child("listofallmembers");
  466. assert(listofallmembers);
  467. for (xml_node member : listofallmembers.children("member"))
  468. {
  469. string prot = member.attribute("prot").value();
  470. assert(!prot.empty());
  471. if (prot != "public")
  472. continue;
  473. xml_attribute ambiguityscope = member.attribute("ambiguityscope");
  474. if (!ambiguityscope.empty())
  475. continue;
  476. string refid = member.attribute("refid").value();
  477. assert(!refid.empty());
  478. result.push_back(refid);
  479. }
  480. return result;
  481. }
  482. static vector<xml_node> GetHiddenMemberdefs(const ClassAnalyzer& classAnalyzer)
  483. {
  484. vector<string> thisRefids = classAnalyzer.GetAllPublicMembersRefids();
  485. vector<ClassAnalyzer> baseClasses = classAnalyzer.GetBaseClasses();
  486. vector<xml_node> result;
  487. for (const ClassAnalyzer& baseClass : baseClasses)
  488. {
  489. vector<string> baseRefids = baseClass.GetAllPublicMembersRefids();
  490. for (const string& baseRefid : baseRefids)
  491. {
  492. if (CONTAINS(thisRefids, baseRefid))
  493. continue;
  494. auto it = SourceData::members_.find(baseRefid);
  495. if (it == SourceData::members_.end())
  496. continue;
  497. xml_node memberdef = it->second;
  498. result.push_back(memberdef);
  499. }
  500. }
  501. return result;
  502. }
  503. vector<string> ClassAnalyzer::GetHiddenMethods() const
  504. {
  505. vector<xml_node> hiddenMemberdefs = GetHiddenMemberdefs(*this);
  506. vector<string> result;
  507. for (xml_node memberdef : hiddenMemberdefs)
  508. {
  509. if (ExtractKind(memberdef) == "function" && !IsStatic(memberdef))
  510. result.push_back(GetFunctionDeclaration(memberdef));
  511. }
  512. sort(result.begin(), result.end());
  513. return result;
  514. }
  515. vector<string> ClassAnalyzer::GetHiddenStaticMethods() const
  516. {
  517. vector<xml_node> hiddenMemberdefs = GetHiddenMemberdefs(*this);
  518. vector<string> result;
  519. for (xml_node memberdef : hiddenMemberdefs)
  520. {
  521. if (ExtractKind(memberdef) == "function" && IsStatic(memberdef))
  522. result.push_back(GetFunctionDeclaration(memberdef));
  523. }
  524. sort(result.begin(), result.end());
  525. return result;
  526. }
  527. vector<string> ClassAnalyzer::GetHiddenFields() const
  528. {
  529. vector<xml_node> hiddenMemberdefs = GetHiddenMemberdefs(*this);
  530. vector<string> result;
  531. for (xml_node memberdef : hiddenMemberdefs)
  532. {
  533. if (ExtractKind(memberdef) == "variable" && !IsStatic(memberdef))
  534. result.push_back(GetVariableDeclaration(memberdef));
  535. }
  536. sort(result.begin(), result.end());
  537. return result;
  538. }
  539. vector<string> ClassAnalyzer::GetHiddenStaticFields() const
  540. {
  541. vector<xml_node> hiddenMemberdefs = GetHiddenMemberdefs(*this);
  542. vector<string> result;
  543. for (xml_node memberdef : hiddenMemberdefs)
  544. {
  545. if (ExtractKind(memberdef) == "variable" && IsStatic(memberdef))
  546. result.push_back(GetVariableDeclaration(memberdef));
  547. }
  548. sort(result.begin(), result.end());
  549. return result;
  550. }
  551. int ClassAnalyzer::GetInherianceDeep(int counter) const
  552. {
  553. vector<ClassAnalyzer> baseClasses = GetBaseClasses();
  554. int result = counter;
  555. for (const ClassAnalyzer& baseClass : baseClasses)
  556. {
  557. int ret = baseClass.GetInherianceDeep(counter + 1);
  558. if (ret > result)
  559. result = ret;
  560. }
  561. return result;
  562. }
  563. vector<MethodAnalyzer> ClassAnalyzer::GetAllMethods() const
  564. {
  565. vector<MethodAnalyzer> result;
  566. vector<xml_node> memberdefs = GetMemberdefs();
  567. for (xml_node memberdef : memberdefs)
  568. {
  569. if (ExtractKind(memberdef) == "function")
  570. result.push_back(MethodAnalyzer(*this, memberdef));
  571. }
  572. return result;
  573. }
  574. vector<MethodAnalyzer> ClassAnalyzer::GetAllPublicMethods() const
  575. {
  576. vector<MethodAnalyzer> result;
  577. vector<xml_node> memberdefs = GetMemberdefs();
  578. for (xml_node memberdef : memberdefs)
  579. {
  580. if (ExtractKind(memberdef) == "function" && ExtractProt(memberdef) == "public")
  581. result.push_back(MethodAnalyzer(*this, memberdef));
  582. }
  583. return result;
  584. }
  585. vector<MethodAnalyzer> ClassAnalyzer::GetThisPublicMethods() const
  586. {
  587. vector<MethodAnalyzer> result;
  588. xml_node sectiondef = FindSectiondef(compounddef_, "public-func");
  589. for (xml_node memberdef : sectiondef.children("memberdef"))
  590. {
  591. MethodAnalyzer methodAnalyzer(*this, memberdef);
  592. result.push_back(methodAnalyzer);
  593. }
  594. return result;
  595. }
  596. vector<MethodAnalyzer> ClassAnalyzer::GetThisPublicStaticMethods() const
  597. {
  598. vector<MethodAnalyzer> result;
  599. xml_node sectiondef = FindSectiondef(compounddef_, "public-static-func");
  600. for (xml_node memberdef : sectiondef.children("memberdef"))
  601. {
  602. MethodAnalyzer methodAnalyzer(*this, memberdef);
  603. result.push_back(methodAnalyzer);
  604. }
  605. return result;
  606. }
  607. vector<FieldAnalyzer> ClassAnalyzer::GetAllFields() const
  608. {
  609. vector<FieldAnalyzer> result;
  610. vector<xml_node> memberdefs = GetMemberdefs();
  611. for (xml_node memberdef : memberdefs)
  612. {
  613. if (ExtractKind(memberdef) == "variable")
  614. result.push_back(FieldAnalyzer(*this, memberdef));
  615. }
  616. return result;
  617. }
  618. vector<FieldAnalyzer> ClassAnalyzer::GetThisPublicFields() const
  619. {
  620. vector<FieldAnalyzer> result;
  621. xml_node sectiondef = FindSectiondef(compounddef_, "public-attrib");
  622. for (xml_node memberdef : sectiondef.children("memberdef"))
  623. {
  624. FieldAnalyzer fieldAnalyzer(*this, memberdef);
  625. result.push_back(fieldAnalyzer);
  626. }
  627. return result;
  628. }
  629. vector<FieldAnalyzer> ClassAnalyzer::GetThisPublicStaticFields() const
  630. {
  631. vector<FieldAnalyzer> result;
  632. xml_node sectiondef = FindSectiondef(compounddef_, "public-static-attrib");
  633. for (xml_node memberdef : sectiondef.children("memberdef"))
  634. {
  635. FieldAnalyzer fieldAnalyzer(*this, memberdef);
  636. result.push_back(fieldAnalyzer);
  637. }
  638. return result;
  639. }
  640. bool ClassAnalyzer::ContainsMethod(const string& name) const
  641. {
  642. vector<MethodAnalyzer> methods = GetAllMethods();
  643. for (const MethodAnalyzer& method : methods)
  644. {
  645. if (method.GetName() == name)
  646. return true;
  647. }
  648. return false;
  649. }
  650. shared_ptr<MethodAnalyzer> ClassAnalyzer::GetMethod(const string& name) const
  651. {
  652. vector<MethodAnalyzer> methods = GetAllMethods();
  653. for (const MethodAnalyzer& method : methods)
  654. {
  655. if (method.GetName() == name)
  656. return make_shared<MethodAnalyzer>(method);
  657. }
  658. return nullptr;
  659. }
  660. int ClassAnalyzer::NumMethods(const string& name) const
  661. {
  662. int result = 0;
  663. vector<MethodAnalyzer> methods = GetAllMethods();
  664. for (const MethodAnalyzer& method : methods)
  665. {
  666. if (method.GetName() == name)
  667. result++;
  668. }
  669. return result;
  670. }
  671. bool ClassAnalyzer::IsAbstract() const
  672. {
  673. vector<MethodAnalyzer> methods = GetAllMethods();
  674. for (const MethodAnalyzer& method : methods)
  675. {
  676. if (method.IsPureVirtual())
  677. {
  678. if (!IsRefCounted())
  679. return true;
  680. // Some pure virtual functions is implemented by URHO3D_OBJECT
  681. string name = method.GetName();
  682. if (name == "GetType" || name == "GetTypeInfo" || name == "GetTypeName")
  683. {
  684. if (ContainsMethod("URHO3D_OBJECT"))
  685. continue;
  686. }
  687. return true;
  688. }
  689. }
  690. return false;
  691. }
  692. bool ClassAnalyzer::AllFloats() const
  693. {
  694. if (Contains(GetComment(), "ALL_FLOATS")) // TODO: remove
  695. return true;
  696. vector<FieldAnalyzer> fields = GetAllFields();
  697. for (const FieldAnalyzer& field : fields)
  698. {
  699. if (field.IsStatic())
  700. continue;
  701. string type = field.GetType().ToString();
  702. if (type != "float" && type != "double")
  703. return false;
  704. }
  705. return true;
  706. }
  707. bool ClassAnalyzer::AllInts() const
  708. {
  709. if (Contains(GetComment(), "ALL_INTS")) // TODO: remove
  710. return true;
  711. vector<FieldAnalyzer> fields = GetAllFields();
  712. for (const FieldAnalyzer& field : fields)
  713. {
  714. if (field.IsStatic())
  715. continue;
  716. string type = field.GetType().ToString();
  717. if (type != "int" && type != "unsigned")
  718. return false;
  719. }
  720. return true;
  721. }
  722. bool ClassAnalyzer::IsPod() const
  723. {
  724. bool result = Contains(GetComment(), "IS_POD");
  725. if (AllFloats() || AllInts())
  726. result = true;
  727. return result;
  728. }
  729. shared_ptr<ClassAnalyzer> ClassAnalyzer::GetBaseClass() const
  730. {
  731. xml_node basecompoundref = compounddef_.child("basecompoundref");
  732. if (!basecompoundref)
  733. return shared_ptr<ClassAnalyzer>();
  734. string refid = basecompoundref.attribute("refid").value();
  735. assert(!refid.empty());
  736. auto it = SourceData::classesByID_.find(refid);
  737. if (it == SourceData::classesByID_.end())
  738. return shared_ptr<ClassAnalyzer>();
  739. xml_node compounddef = it->second;
  740. return make_shared<ClassAnalyzer>(compounddef);
  741. }
  742. vector<ClassAnalyzer> ClassAnalyzer::GetBaseClasses() const
  743. {
  744. // Workaround for bug in doxygen 1.9+
  745. // https://github.com/doxygen/doxygen/issues/8805
  746. // This can be removed in future
  747. vector<string> pushed_refids;
  748. vector<ClassAnalyzer> result;
  749. for (xml_node basecompoundref : compounddef_.children("basecompoundref"))
  750. {
  751. string refid = basecompoundref.attribute("refid").value();
  752. if (refid.empty()) // Type from ThirdParty lib
  753. continue;
  754. auto it = SourceData::classesByID_.find(refid);
  755. if (it == SourceData::classesByID_.end())
  756. continue;
  757. // This can be removed in future
  758. if (CONTAINS(pushed_refids, refid))
  759. continue;
  760. pushed_refids.push_back(refid);
  761. xml_node compounddef = it->second;
  762. result.push_back(ClassAnalyzer(compounddef));
  763. }
  764. return result;
  765. }
  766. inline bool Contains(const vector<ClassAnalyzer>& classes, const ClassAnalyzer& cl)
  767. {
  768. for (const ClassAnalyzer& c : classes)
  769. {
  770. // Comparison without template specialization
  771. if (c.GetCompounddef() == cl.GetCompounddef())
  772. return true;
  773. }
  774. return false;
  775. }
  776. static void RecursivelyGetBaseClasses(const ClassAnalyzer& analyzer, vector<ClassAnalyzer>& result)
  777. {
  778. for (const ClassAnalyzer& baseClass : analyzer.GetBaseClasses())
  779. {
  780. if (!Contains(result, baseClass))
  781. result.push_back(baseClass);
  782. RecursivelyGetBaseClasses(baseClass, result);
  783. }
  784. }
  785. vector<ClassAnalyzer> ClassAnalyzer::GetAllBaseClasses() const
  786. {
  787. vector<ClassAnalyzer> result;
  788. RecursivelyGetBaseClasses(*this, result);
  789. return result;
  790. }
  791. vector<ClassAnalyzer> ClassAnalyzer::GetDerivedClasses() const
  792. {
  793. vector<ClassAnalyzer> result;
  794. for (xml_node basecompoundref : compounddef_.children("derivedcompoundref"))
  795. {
  796. string refid = basecompoundref.attribute("refid").value();
  797. if (refid.empty()) // Type from ThirdParty lib
  798. continue;
  799. auto it = SourceData::classesByID_.find(refid);
  800. if (it == SourceData::classesByID_.end())
  801. continue;
  802. xml_node compounddef = it->second;
  803. result.push_back(ClassAnalyzer(compounddef));
  804. }
  805. return result;
  806. }
  807. static void RecursivelyGetDerivedClasses(const ClassAnalyzer& analyzer, vector<ClassAnalyzer>& result)
  808. {
  809. for (const ClassAnalyzer& derivedClass : analyzer.GetDerivedClasses())
  810. {
  811. if (!Contains(result, derivedClass))
  812. result.push_back(derivedClass);
  813. RecursivelyGetDerivedClasses(derivedClass, result);
  814. }
  815. }
  816. vector<ClassAnalyzer> ClassAnalyzer::GetAllDerivedClasses() const
  817. {
  818. vector<ClassAnalyzer> result;
  819. RecursivelyGetDerivedClasses(*this, result);
  820. return result;
  821. }
  822. bool ClassAnalyzer::HasThisConstructor() const
  823. {
  824. vector<MethodAnalyzer> methods = GetAllMethods();
  825. for (const MethodAnalyzer& method : methods)
  826. {
  827. if (method.IsThisConstructor())
  828. return true;
  829. }
  830. return false;
  831. }
  832. bool ClassAnalyzer::IsRefCounted() const
  833. {
  834. if (GetClassName() == "RefCounted")
  835. return true;
  836. vector<ClassAnalyzer> baseClasses = GetAllBaseClasses();
  837. for (const ClassAnalyzer& classAnalyzer : baseClasses)
  838. {
  839. if (classAnalyzer.GetClassName() == "RefCounted")
  840. return true;
  841. }
  842. return false;
  843. }
  844. shared_ptr<MethodAnalyzer> ClassAnalyzer::GetDefinedThisDefaultConstructor() const
  845. {
  846. vector<MethodAnalyzer> methods = GetAllMethods();
  847. for (const MethodAnalyzer& method : methods)
  848. {
  849. if (method.IsThisDefaultConstructor())
  850. return make_shared<MethodAnalyzer>(method);
  851. }
  852. return nullptr;
  853. }
  854. vector<MethodAnalyzer> ClassAnalyzer::GetThisNonDefaultConstructors() const
  855. {
  856. vector<MethodAnalyzer> result;
  857. vector<MethodAnalyzer> methods = GetAllMethods();
  858. for (const MethodAnalyzer& method : methods)
  859. {
  860. if (method.IsThisNonDefaultConstructor())
  861. result.push_back(method);
  862. }
  863. return result;
  864. }
  865. // ============================================================================
  866. FunctionAnalyzer::FunctionAnalyzer(xml_node memberdef, const TemplateSpecialization& specialization)
  867. : memberdef_(memberdef)
  868. , specialization_(specialization)
  869. {
  870. assert(IsMemberdef(memberdef));
  871. assert(ExtractKind(memberdef) == "function");
  872. }
  873. // ============================================================================
  874. MethodAnalyzer::MethodAnalyzer(const ClassAnalyzer& classAnalyzer, xml_node memberdef, const TemplateSpecialization& specialization)
  875. : FunctionAnalyzer(memberdef, specialization)
  876. , classAnalyzer_(classAnalyzer)
  877. {
  878. // Append template specialization from class
  879. specialization_.insert(classAnalyzer.GetSpecialization().begin(), classAnalyzer.GetSpecialization().end());
  880. }
  881. string MethodAnalyzer::GetVirt() const
  882. {
  883. string result = memberdef_.attribute("virt").value();
  884. assert(!result.empty());
  885. return result;
  886. }
  887. string MethodAnalyzer::GetContainsClassName() const
  888. {
  889. string argsstring = ExtractArgsstring(memberdef_);
  890. assert(!argsstring.empty());
  891. string prototype = ExtractDefinition(memberdef_) + argsstring;
  892. smatch match;
  893. regex_match(prototype, match, regex(".*Urho3D::(.+?)::.*"));
  894. assert(match.size());
  895. string result = match[1].str();
  896. return result;
  897. }
  898. /*
  899. string FieldAnalyzer::GetDeclaration() const
  900. {
  901. string definition = ExtractDefinition(memberdef_);
  902. assert(!definition.empty());
  903. // Remove Urho3D::
  904. smatch match;
  905. regex_match(definition, match, regex("(.*)Urho3D::(.+)"));
  906. assert(match.size() == 3);
  907. string result = match[1].str() + match[2].str();
  908. result = BeautifyDefinition(result);
  909. return result;
  910. }
  911. */
  912. string GetVariableDeclaration(xml_node memberdef)
  913. {
  914. assert(IsMemberdef(memberdef));
  915. assert(ExtractKind(memberdef) == "variable");
  916. string result = ExtractDefinition(memberdef);
  917. result = RemoveFirst(result, "URHO3D_API ");
  918. result = RemoveFirst(result, " URHO3D_API");
  919. assert(Contains(result, " Urho3D::"));
  920. result = ReplaceFirst(result, " Urho3D::", " ");
  921. if (IsStatic(memberdef))
  922. result = "static " + result;
  923. result = BeautifyDefinition(result);
  924. return result;
  925. }
  926. string GetFunctionDeclaration(xml_node memberdef)
  927. {
  928. assert(IsMemberdef(memberdef));
  929. assert(ExtractKind(memberdef) == "function");
  930. string argsstring = ExtractArgsstring(memberdef);
  931. assert(!argsstring.empty());
  932. string prototype = ExtractDefinition(memberdef) + argsstring;
  933. smatch match;
  934. regex_match(prototype, match, regex("([^(]*)Urho3D::(.+?)"));
  935. assert(match.size());
  936. string result = match[1].str() + match[2].str();
  937. if (IsExplicit(memberdef))
  938. result = "explicit " + result;
  939. if (IsTemplate(memberdef))
  940. {
  941. string t = "";
  942. xml_node templateparamlist = memberdef.child("templateparamlist");
  943. for (xml_node param : templateparamlist.children("param"))
  944. {
  945. if (t.length() > 0)
  946. t += ", ";
  947. xml_node type = param.child("type");
  948. assert(type);
  949. t += type.child_value();
  950. xml_node declname = param.child("declname");
  951. if (!declname.empty())
  952. t += " " + string(declname.child_value());
  953. }
  954. result = "template<" + t + "> " + result;
  955. }
  956. result = RemoveFirst(result, "URHO3D_API ");
  957. result = RemoveFirst(result, " URHO3D_API");
  958. result = BeautifyDefinition(result);
  959. return result;
  960. }
  961. string GetFunctionLocation(xml_node memberdef)
  962. {
  963. return GetFunctionDeclaration(memberdef) + " | File: " + ExtractHeaderFile(memberdef);
  964. }
  965. bool MethodAnalyzer::IsConst() const
  966. {
  967. string constAttr = memberdef_.attribute("const").value();
  968. assert(!constAttr.empty());
  969. return constAttr == "yes";
  970. }
  971. bool MethodAnalyzer::CanBeGetProperty() const
  972. {
  973. string returnType = GetReturnType().ToString();
  974. if (returnType == "void" || returnType.empty())
  975. return false;
  976. if (GetParams().size() != 0 && GetParams().size() != 1)
  977. return false;
  978. return true;
  979. }
  980. bool MethodAnalyzer::CanBeSetProperty() const
  981. {
  982. string returnType = GetReturnType().ToString();
  983. if (returnType != "void")
  984. return false;
  985. if (GetParams().size() != 1 && GetParams().size() != 2)
  986. return false;
  987. return true;
  988. }
  989. bool MethodAnalyzer::IsParentDestructor() const
  990. {
  991. string functionName = GetName();
  992. if (!StartsWith(functionName, "~"))
  993. return false;
  994. return !IsThisDestructor();
  995. }
  996. bool MethodAnalyzer::IsConstructor() const
  997. {
  998. string name = GetName();
  999. return ExtractDefinition(memberdef_) == "Urho3D::" + name + "::" + name;
  1000. }
  1001. bool MethodAnalyzer::IsDestructor() const
  1002. {
  1003. string name = GetName();
  1004. return StartsWith(name, "~");
  1005. }
  1006. bool MethodAnalyzer::IsParentConstructor() const
  1007. {
  1008. if (IsThisConstructor())
  1009. return false;
  1010. string name = GetName();
  1011. return ExtractDefinition(memberdef_) == "Urho3D::" + name + "::" + name;
  1012. }
  1013. shared_ptr<MethodAnalyzer> MethodAnalyzer::Reimplements() const
  1014. {
  1015. xml_node reimplements = memberdef_.child("reimplements");
  1016. if (!reimplements)
  1017. return shared_ptr<MethodAnalyzer>();
  1018. string refid = reimplements.attribute("refid").value();
  1019. assert(!refid.empty());
  1020. auto it = SourceData::members_.find(refid);
  1021. if (it == SourceData::members_.end())
  1022. return shared_ptr<MethodAnalyzer>();
  1023. xml_node memberdef = it->second;
  1024. return make_shared<MethodAnalyzer>(classAnalyzer_, memberdef);
  1025. }
  1026. // ============================================================================
  1027. FieldAnalyzer::FieldAnalyzer(ClassAnalyzer classAnalyzer, xml_node memberdef)
  1028. : classAnalyzer_(classAnalyzer)
  1029. , memberdef_(memberdef)
  1030. {
  1031. assert(IsMemberdef(memberdef));
  1032. assert(ExtractKind(memberdef) == "variable");
  1033. }
  1034. string FieldAnalyzer::GetLocation() const
  1035. {
  1036. string result = GetDeclaration();
  1037. result += " | File: " + GetHeaderFile();
  1038. if (!classAnalyzer_.usingLocation_.empty())
  1039. result = classAnalyzer_.usingLocation_ + " | " + result;
  1040. return result;
  1041. }
  1042. // ============================================================================
  1043. NamespaceAnalyzer::NamespaceAnalyzer(xml_node compounddef)
  1044. : compounddef_(compounddef)
  1045. {
  1046. assert(IsCompounddef(compounddef));
  1047. assert(ExtractKind(compounddef) == "namespace");
  1048. }
  1049. vector<EnumAnalyzer> NamespaceAnalyzer::GetEnums()
  1050. {
  1051. xml_node sectiondef = FindSectiondef(compounddef_, "enum");
  1052. assert(sectiondef);
  1053. vector<EnumAnalyzer> result;
  1054. for (xml_node memberdef : sectiondef.children("memberdef"))
  1055. {
  1056. EnumAnalyzer analyzer(memberdef);
  1057. result.push_back(analyzer);
  1058. }
  1059. return result;
  1060. }
  1061. vector<GlobalVariableAnalyzer> NamespaceAnalyzer::GetVariables()
  1062. {
  1063. xml_node sectiondef = FindSectiondef(compounddef_, "var");
  1064. assert(sectiondef);
  1065. vector<GlobalVariableAnalyzer> result;
  1066. for (xml_node memberdef : sectiondef.children("memberdef"))
  1067. result.push_back(GlobalVariableAnalyzer(memberdef));
  1068. return result;
  1069. }
  1070. vector<GlobalFunctionAnalyzer> NamespaceAnalyzer::GetFunctions()
  1071. {
  1072. xml_node sectiondef = FindSectiondef(compounddef_, "func");
  1073. assert(sectiondef);
  1074. vector<GlobalFunctionAnalyzer> result;
  1075. for (xml_node memberdef : sectiondef.children("memberdef"))
  1076. result.push_back(GlobalFunctionAnalyzer(memberdef));
  1077. return result;
  1078. }
  1079. // ============================================================================
  1080. UsingAnalyzer::UsingAnalyzer(xml_node memberdef)
  1081. : memberdef_(memberdef)
  1082. {
  1083. assert(IsMemberdef(memberdef));
  1084. assert(ExtractKind(memberdef) == "typedef");
  1085. }
  1086. // ============================================================================
  1087. GlobalFunctionAnalyzer::GlobalFunctionAnalyzer(xml_node memberdef, const TemplateSpecialization& specialization)
  1088. : FunctionAnalyzer(memberdef, specialization)
  1089. {
  1090. }
  1091. // ============================================================================
  1092. ClassStaticFunctionAnalyzer::ClassStaticFunctionAnalyzer(const ClassAnalyzer& classAnalyzer, xml_node memberdef, const TemplateSpecialization& specialization)
  1093. : FunctionAnalyzer(memberdef, specialization)
  1094. , classAnalyzer_(classAnalyzer)
  1095. {
  1096. assert(IsStatic(memberdef));
  1097. }