1 /**
2 	Merges eponymous templates to a single definition with template arguments.
3 
4 	Copyright: © 2012-2015 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..string : strip;
19 
20 	void processDecls(ref Declaration[] decls)
21 	{
22 		Declaration[] new_decls;
23 		foreach (d; decls) {
24 			if (auto templ = cast(TemplateDeclaration)d) {
25 				// process members recursively
26 				processDecls(templ.members);
27 
28 				// search for eponymous template members
29 				Declaration[] epmembers;
30 				bool[DocGroup] augmented_groups;
31 				foreach (m; templ.members)
32 					if (m.name == templ.name) {
33 						// if we encounter any templated member, skip the
34 						// eponymous merge and show individual members instead.
35 						if (cast(TemplateDeclaration)m || m.templateArgs.length) {
36 							epmembers = null;
37 							break;
38 						}
39 
40 						// if both, the parent template and the member are documented,
41 						// abort the merge
42 						if (templ.docGroup.text.strip.length && m.docGroup.text.strip.length) {
43 							epmembers = null;
44 							break;
45 						}
46 
47 						m.templateArgs = templ.templateArgs;
48 						m.templateConstraint = templ.templateConstraint;
49 						m.isTemplate = true;
50 						m.protection = templ.protection;
51 						m.parent = templ.parent;
52 						if (templ.docGroup.text.strip.length) m.docGroup = templ.docGroup;
53 						m.inheritingDecl = templ.inheritingDecl;
54 						epmembers ~= m;
55 					}
56 
57 				if (epmembers.length > 0) {
58 					// if we found some, replace all references of the original template with the new modified members
59 					foreach (i, m; templ.docGroup.members) {
60 						if (m !is templ) continue;
61 						auto newm = templ.docGroup.members[0 .. i];
62 						foreach (epm; epmembers)
63 							if (epm.docGroup is templ.docGroup)
64 								newm ~= epm;
65 						newm ~= templ.docGroup.members[i+1 .. $];
66 						templ.docGroup.members = newm;
67 						break;
68 					}
69 					new_decls ~= epmembers;
70 				} else {
71 					// keep the template if there are no eponymous members
72 					new_decls ~= templ;
73 				}
74 			} else new_decls ~= d;
75 
76 			if (auto comp = cast(CompositeTypeDeclaration)d)
77 				processDecls(comp.members);
78 		}
79 		decls = new_decls;
80 	}
81 
82 	root.visit!Module((mod){
83 		processDecls(mod.members);
84 	});
85 }