|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 /** |
|
6 * A script for GCC-dehydra to analyze the Mozilla codebase and catch |
|
7 * patterns that are incorrect, but which cannot be detected by a compiler. */ |
|
8 |
|
9 /** |
|
10 * Activate Treehydra outparams analysis if running in Treehydra. |
|
11 */ |
|
12 |
|
13 function treehydra_enabled() { |
|
14 return this.hasOwnProperty('TREE_CODE'); |
|
15 } |
|
16 |
|
17 sys.include_path.push(options.topsrcdir); |
|
18 |
|
19 include('string-format.js'); |
|
20 |
|
21 let modules = []; |
|
22 |
|
23 function LoadModules(modulelist) |
|
24 { |
|
25 if (modulelist == "") |
|
26 return; |
|
27 |
|
28 let modulenames = modulelist.split(','); |
|
29 for each (let modulename in modulenames) { |
|
30 let module = { __proto__: this }; |
|
31 include(modulename, module); |
|
32 modules.push(module); |
|
33 } |
|
34 } |
|
35 |
|
36 LoadModules(options['dehydra-modules']); |
|
37 if (treehydra_enabled()) |
|
38 LoadModules(options['treehydra-modules']); |
|
39 |
|
40 function process_type(c) |
|
41 { |
|
42 for each (let module in modules) |
|
43 if (module.hasOwnProperty('process_type')) |
|
44 module.process_type(c); |
|
45 } |
|
46 |
|
47 function hasAttribute(c, attrname) |
|
48 { |
|
49 var attr; |
|
50 |
|
51 if (c.attributes === undefined) |
|
52 return false; |
|
53 |
|
54 for each (attr in c.attributes) |
|
55 if (attr.name == 'user' && attr.value[0] == attrname) |
|
56 return true; |
|
57 |
|
58 return false; |
|
59 } |
|
60 |
|
61 // This is useful for detecting method overrides |
|
62 function signaturesMatch(m1, m2) |
|
63 { |
|
64 if (m1.shortName != m2.shortName) |
|
65 return false; |
|
66 |
|
67 if ((!!m1.isVirtual) != (!!m2.isVirtual)) |
|
68 return false; |
|
69 |
|
70 if (m1.isStatic != m2.isStatic) |
|
71 return false; |
|
72 |
|
73 let p1 = m1.type.parameters; |
|
74 let p2 = m2.type.parameters; |
|
75 |
|
76 if (p1.length != p2.length) |
|
77 return false; |
|
78 |
|
79 for (let i = 0; i < p1.length; ++i) |
|
80 if (!params_match(p1[i], p2[i])) |
|
81 return false; |
|
82 |
|
83 return true; |
|
84 } |
|
85 |
|
86 function params_match(p1, p2) |
|
87 { |
|
88 [p1, p2] = unwrap_types(p1, p2); |
|
89 |
|
90 for (let i in p1) |
|
91 if (i == "type" && !types_match(p1.type, p2.type)) |
|
92 return false; |
|
93 else if (i != "type" && p1[i] !== p2[i]) |
|
94 return false; |
|
95 |
|
96 for (let i in p2) |
|
97 if (!(i in p1)) |
|
98 return false; |
|
99 |
|
100 return true; |
|
101 } |
|
102 |
|
103 function types_match(t1, t2) |
|
104 { |
|
105 if (!t1 || !t2) |
|
106 return false; |
|
107 |
|
108 [t1, t2] = unwrap_types(t1, t2); |
|
109 |
|
110 return t1 === t2; |
|
111 } |
|
112 |
|
113 function unwrap_types(t1, t2) |
|
114 { |
|
115 while (t1.variantOf) |
|
116 t1 = t1.variantOf; |
|
117 |
|
118 while (t2.variantOf) |
|
119 t2 = t2.variantOf; |
|
120 |
|
121 return [t1, t2]; |
|
122 } |
|
123 |
|
124 const forward_functions = [ |
|
125 'process_type', |
|
126 'process_tree_type', |
|
127 'process_decl', |
|
128 'process_tree_decl', |
|
129 'process_function', |
|
130 'process_tree', |
|
131 'process_cp_pre_genericize', |
|
132 'input_end' |
|
133 ]; |
|
134 |
|
135 function setup_forwarding(n) |
|
136 { |
|
137 this[n] = function() { |
|
138 for each (let module in modules) { |
|
139 if (module.hasOwnProperty(n)) { |
|
140 module[n].apply(this, arguments); |
|
141 } |
|
142 } |
|
143 } |
|
144 } |
|
145 |
|
146 for each (let n in forward_functions) |
|
147 setup_forwarding(n); |