XmlAnalyzer.cpp 35 KB

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