Bug 400795 - initial form fill and username autocomplete should share common code...
[wine-gecko.git] / xpcom / analysis / stack.js
blob6922a33c7f7f335d1b0d6c2e25e54a754b5f3410
1 include("gcc_util.js");
2 include("unstable/lazy_types.js");
4 function process_type(c)
6 if ((c.kind == 'class' || c.kind == 'struct') &&
7 !c.isIncomplete)
8 isStack(c);
11 /**
12 * A BlameChain records a chain of one or more location/message pairs. It
13 * can be used to issue a complex error message such as:
14 * location: error: Allocated class Foo on the heap
15 * locationofFoo: class Foo inherits from class Bar
16 * locationofBar: in class Bar
17 * locationofBarMem: Member Bar::mFoo
18 * locationofBaz: class Baz is annotated NS_STACK
20 function BlameChain(loc, message, prev)
22 this.loc = loc;
23 this.message = message;
24 this.prev = prev;
26 BlameChain.prototype.toString = function()
28 let loc = this.loc;
29 if (loc === undefined)
30 loc = "<unknown location>";
32 let str = '%s: %s'.format(loc.toString(), this.message);
33 if (this.prev)
34 str += "\n%s".format(this.prev);
35 return str;
38 function isStack(c)
40 function calculate()
42 if (hasAttribute(c, 'NS_stack'))
43 return new BlameChain(c.loc, '%s %s is annotated NS_STACK_CLASS'.format(c.kind, c.name));
45 for each (let base in c.bases) {
46 let r = isStack(base.type);
47 if (r != null)
48 return new BlameChain(c.loc, '%s %s is a base of %s %s'.format(base.type.kind, base.type.name, c.kind, c.name), r);
51 for each (let member in c.members) {
52 if (member.isFunction)
53 continue;
55 if (hasAttribute(member, 'NS_okonheap'))
56 continue;
58 let type = member.type;
59 while (true) {
60 if (type === undefined)
61 break;
63 if (type.isArray) {
64 type = type.type;
65 continue;
68 if (type.typedef) {
69 if (hasAttribute(type, 'NS_stack'))
70 return true;
72 type = type.typedef;
73 continue;
75 break;
78 if (type === undefined) {
79 warning("incomplete type for member " + member + ".", member.loc);
80 continue;
83 if (type.isPointer || type.isReference)
84 continue;
86 if (!type.kind || (type.kind != 'class' && type.kind != 'struct'))
87 continue;
89 let r = isStack(type);
90 if (r != null)
91 return new BlameChain(c.loc, 'In class %s'.format(c.name),
92 new BlameChain(member.loc, 'Member %s'.format(member.name), r));
94 return null;
97 if (c.isIncomplete)
98 throw Error("Can't get stack property for incomplete type.");
100 if (!c.hasOwnProperty('isStack'))
101 c.isStack = calculate();
103 return c.isStack;
106 function isVoidPtr(t)
108 return t.isPointer && t.type.name == 'void';
111 function xrange(start, end, skip)
113 for (;
114 (skip > 0) ? (start < end) : (start > end);
115 start += skip)
116 yield start;
119 function process_cp_pre_genericize(fndecl)
121 function findconstructors(t, stack)
123 function getLocation() {
124 let loc = location_of(t);
125 if (loc !== undefined)
126 return loc;
128 for (let i = stack.length - 1; i >= 0; --i) {
129 loc = location_of(stack[i]);
130 if (loc !== undefined)
131 return loc;
133 return location_of(DECL_SAVED_TREE(fndecl));
136 try {
137 t.tree_check(CALL_EXPR);
138 let fncall =
139 callable_arg_function_decl(CALL_EXPR_FN(t));
140 if (fncall == null)
141 return;
143 let nameid = DECL_NAME(fncall);
144 if (IDENTIFIER_OPNAME_P(nameid)) {
145 let name = IDENTIFIER_POINTER(nameid);
147 if (name == "operator new" || name == "operator new []") {
148 let fncallobj = dehydra_convert(TREE_TYPE(fncall));
149 if (fncallobj.parameters.length == 2 &&
150 isVoidPtr(fncallobj.parameters[1]))
151 return;
153 let i;
154 for (i in xrange(stack.length - 1, -1, -1)) {
155 if (TREE_CODE(stack[i]) != NOP_EXPR)
156 break;
158 let assign = stack[i];
159 switch (TREE_CODE(assign)) {
160 case VAR_DECL:
161 break;
163 case INIT_EXPR:
164 case MODIFY_EXPR:
165 case TARGET_EXPR:
166 assign = assign.operands()[1];
167 break;
169 case CALL_EXPR:
170 assign = stack[i + 1];
171 break;
173 default:
174 error("Unrecognized assignment from operator new: " + TREE_CODE(assign), getLocation());
175 return;
178 let destType = dehydra_convert(TREE_TYPE(assign));
179 if (!destType.isPointer && !destType.isReference) {
180 error("operator new not assigned to pointer/ref?", getLocation());
181 return;
183 destType = destType.type;
185 let r = isStack(destType);
186 if (r)
187 error("constructed object of type '%s' not on the stack: %s".format(destType.name, r), getLocation());
191 catch (e if e.TreeCheckError) { }
194 if (hasAttribute(dehydra_convert(fndecl), 'NS_suppress_stackcheck'))
195 return;
197 walk_tree(DECL_SAVED_TREE(fndecl), findconstructors);