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