1 /**
2 	Inherits non-existing members and documentation from anchestor classes/intefaces.
3 
4 	Copyright: © 2012 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.inherit;
9 
10 import ddox.api;
11 import ddox.entities;
12 
13 import std.algorithm : map;
14 
15 
16 void inheritDocs(Package root)
17 {
18 	bool[CompositeTypeDeclaration] visited;
19 	
20 	bool matches(Declaration a, Declaration b)
21 	{
22 		if (a.kind != b.kind) return false;
23 		if (a.name != b.name) return false;
24 		if (auto ctm = cast(TypedDeclaration)a)
25 			if (ctm.type != (cast(TypedDeclaration)b).type)
26 				return false;
27 		return true;
28 	}
29 
30 	Declaration findMatching(Declaration[] pool, Declaration match)
31 	{
32 		foreach (m; pool) {
33 			if (matches(m, match))
34 				return m;
35 		}
36 		return null;
37 	}
38 
39 	void inheritMembers(CompositeTypeDeclaration decl, Declaration[] parentmembers, const(Declaration) parent)
40 	{
41 		foreach (parentgrp; docGroups(parentmembers)) {
42 			DocGroup inhgrp;
43 			foreach (parentmem; parentgrp.members.map!(m => cast(Declaration)m)()) {
44 				if (parentmem.name == "this") continue;
45 				auto childmem = findMatching(decl.members, parentmem);
46 				if (!childmem || !childmem.docGroup.text.length) {
47 					Declaration newdecl;
48 					if (childmem) newdecl = childmem;
49 					else newdecl = parentmem.dup;
50 					if (!inhgrp) inhgrp = new DocGroup(newdecl, parentgrp.text);
51 					else inhgrp.members ~= newdecl;
52 					newdecl.docGroup = inhgrp;
53 					if (!childmem) {
54 						newdecl.inheritingDecl = parentmem;
55 						assert(newdecl.inheritingDecl && newdecl.inheritingDecl !is newdecl);
56 						decl.members ~= newdecl;
57 					}
58 				}
59 			}
60 		}
61 	}
62 
63 	void scanInterface(InterfaceDeclaration decl)
64 	{
65 		if (decl in visited) return;
66 		foreach (i; decl.derivedInterfaces)
67 			if (i.typeDecl)
68 				scanInterface(cast(InterfaceDeclaration)i.typeDecl);
69 		visited[decl] = true;
70 
71 		foreach (it; decl.derivedInterfaces)
72 			if (it.typeDecl)
73 				inheritMembers(decl, (cast(InterfaceDeclaration)it.typeDecl).members, it.typeDecl);
74 	}
75 
76 	void scanClass(ClassDeclaration decl)
77 	{
78 		if (decl in visited) return;
79 
80 		visited[decl] = true;
81 
82 		if (decl.baseClass && decl.baseClass.typeDecl) scanClass(cast(ClassDeclaration)decl.baseClass.typeDecl);
83 
84 		foreach (i; decl.derivedInterfaces)
85 			if (i.typeDecl)
86 				scanInterface(cast(InterfaceDeclaration)i.typeDecl);
87 
88 		if (decl.baseClass && decl.baseClass.typeDecl)
89 			inheritMembers(decl, (cast(ClassDeclaration)decl.baseClass.typeDecl).members, decl.baseClass.typeDecl);
90 		foreach (i; decl.derivedInterfaces)
91 			if (i.typeDecl)
92 				inheritMembers(decl, (cast(InterfaceDeclaration)i.typeDecl).members, i.typeDecl);
93 	}
94 
95 	void scanComposite(CompositeTypeDeclaration decl)
96 	{
97 		if (auto cd = cast(ClassDeclaration)decl) scanClass(cd);
98 		else if (auto cd = cast(InterfaceDeclaration)decl) scanInterface(cd);
99 		else {
100 			foreach (m; decl.members)
101 				if (auto dc = cast(CompositeTypeDeclaration)m)
102 					scanComposite(dc);
103 		}
104 	}
105 
106 	void scanModule(Module mod)
107 	{
108 		foreach (d; mod.members)
109 			if (auto dc = cast(CompositeTypeDeclaration)d)
110 				scanComposite(dc);
111 	}
112 
113 	void scanPackage(Package pack)
114 	{
115 		foreach (p; pack.packages)
116 			scanPackage(p);
117 		foreach (m; pack.modules)
118 			scanModule(m);
119 	}
120 
121 	scanPackage(root);
122 }