1 /** 2 Merges eponymous templates to a single definition with template arguments. 3 4 Copyright: © 2012-2016 RejectedSoftware e.K. 5 License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. 6 Authors: Sönke Ludwig 7 */ 8 module ddox.processors.eptemplates; 9 10 import ddox.api; 11 import ddox.entities; 12 13 import std.algorithm; 14 15 16 void mergeEponymousTemplates(Package root) 17 { 18 import std.array : array; 19 import std.string : strip; 20 21 static bool canMerge(TemplateDeclaration templ, Declaration m) 22 { 23 // if we encounter any templated member, skip the 24 // eponymous merge to avoid hiding the nested template 25 // arguments/constraints 26 if (cast(TemplateDeclaration)m || m.isTemplate) return false; 27 28 // if both, the parent template and the member are documented, 29 // abort the merge, so that the member documentation is shown 30 // individually 31 if (templ.docGroup.text.strip.length && m.docGroup.text.strip.length) 32 return false; 33 return true; 34 } 35 36 void processDecls(ref Declaration[] decls) 37 { 38 Declaration[] new_decls; 39 foreach (d; decls) { 40 if (auto templ = cast(TemplateDeclaration)d) { 41 // process members recursively 42 processDecls(templ.members); 43 44 // search for eponymous template members 45 Declaration[] epmembers = templ.members.filter!(m => m.name == templ.name).array; 46 if (!epmembers.length || !epmembers.all!(m => canMerge(templ, m))) { 47 // keep the template if there are no eponymous members or not all are mergeable 48 new_decls ~= templ; 49 continue; 50 } 51 52 foreach (m; epmembers) { 53 m.templateArgs = templ.templateArgs; 54 m.templateConstraint = templ.templateConstraint; 55 m.isTemplate = true; 56 m.protection = templ.protection; 57 m.parent = templ.parent; 58 if (templ.docGroup.text.strip.length) m.docGroup = templ.docGroup; 59 m.inheritingDecl = templ.inheritingDecl; 60 } 61 62 // if we found some, replace all references of the original template with the new modified members 63 foreach (i, m; templ.docGroup.members) { 64 if (m !is templ) continue; 65 auto newm = templ.docGroup.members[0 .. i]; 66 foreach (epm; epmembers) 67 if (epm.docGroup is templ.docGroup) 68 newm ~= epm; 69 newm ~= templ.docGroup.members[i+1 .. $]; 70 templ.docGroup.members = newm; 71 break; 72 } 73 new_decls ~= epmembers; 74 } else { 75 if (auto comp = cast(CompositeTypeDeclaration)d) 76 processDecls(comp.members); 77 78 new_decls ~= d; 79 } 80 } 81 decls = new_decls; 82 } 83 84 root.visit!Module((Module mod){ 85 processDecls(mod.members); 86 }); 87 }