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 		if (decl.baseClass && decl.baseClass.typeDecl) scanClass(cast(ClassDeclaration)decl.baseClass.typeDecl);
77 		foreach (i; decl.derivedInterfaces)
78 			if (i.typeDecl)
79 				scanInterface(cast(InterfaceDeclaration)i.typeDecl);
80 
81 		visited[decl] = true;
82 		if (decl.baseClass && decl.baseClass.typeDecl)
83 			inheritMembers(decl, (cast(ClassDeclaration)decl.baseClass.typeDecl).members, decl.baseClass.typeDecl);
84 		foreach (i; decl.derivedInterfaces)
85 			if (i.typeDecl)
86 				inheritMembers(decl, (cast(InterfaceDeclaration)i.typeDecl).members, i.typeDecl);
87 	}
88 
89 	void scanComposite(CompositeTypeDeclaration decl)
90 	{
91 		if (auto cd = cast(ClassDeclaration)decl) scanClass(cd);
92 		else if (auto cd = cast(InterfaceDeclaration)decl) scanInterface(cd);
93 		else {
94 			foreach (m; decl.members)
95 				if (auto dc = cast(CompositeTypeDeclaration)m)
96 					scanComposite(dc);
97 		}
98 	}
99 
100 	void scanModule(Module mod)
101 	{
102 		foreach (d; mod.members)
103 			if (auto dc = cast(CompositeTypeDeclaration)d)
104 				scanComposite(dc);
105 	}
106 
107 	void scanPackage(Package pack)
108 	{
109 		foreach (p; pack.packages)
110 			scanPackage(p);
111 		foreach (m; pack.modules)
112 			scanModule(m);
113 	}
114 
115 	scanPackage(root);
116 }