Line data Source code
1 : /* valainterface.vala
2 : *
3 : * Copyright (C) 2006-2010 Jürg Billeter
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Lesser General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2.1 of the License, or (at your option) any later version.
9 :
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Lesser General Public License for more details.
14 :
15 : * You should have received a copy of the GNU Lesser General Public
16 : * License along with this library; if not, write to the Free Software
17 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 : *
19 : * Author:
20 : * Jürg Billeter <j@bitron.ch>
21 : */
22 :
23 : using GLib;
24 :
25 : /**
26 : * Represents an interface declaration in the source code.
27 : */
28 118682 : public class Vala.Interface : ObjectTypeSymbol {
29 117152 : private List<DataType> prerequisites = new ArrayList<DataType> ();
30 :
31 117152 : private List<Symbol> virtuals = new ArrayList<Symbol> ();
32 :
33 : /**
34 : * Creates a new interface.
35 : *
36 : * @param name type name
37 : * @param source_reference reference to source code
38 : * @return newly created interface
39 : */
40 175728 : public Interface (string name, SourceReference? source_reference = null, Comment? comment = null) {
41 58576 : base (name, source_reference, comment);
42 : }
43 :
44 : /**
45 : * Adds the specified interface or class to the list of prerequisites of
46 : * this interface.
47 : *
48 : * @param type an interface or class reference
49 : */
50 73594 : public void add_prerequisite (DataType type) {
51 73594 : prerequisites.add (type);
52 73594 : type.parent_node = this;
53 : }
54 :
55 : /**
56 : * Returns the base type list.
57 : *
58 : * @return list of base types
59 : */
60 577079 : public unowned List<DataType> get_prerequisites () {
61 577079 : return prerequisites;
62 : }
63 :
64 : /**
65 : * Adds the specified method as a member to this interface.
66 : *
67 : * @param m a method
68 : */
69 573779 : public override void add_method (Method m) {
70 573779 : if (m is CreationMethod) {
71 1 : Report.error (m.source_reference, "construction methods may only be declared within classes and structs");
72 :
73 1 : m.error = true;
74 1 : return;
75 : }
76 573778 : if (m.binding != MemberBinding.STATIC) {
77 507291 : m.this_parameter = new Parameter ("this", SemanticAnalyzer.get_this_type (m, this), m.source_reference);
78 507291 : m.scope.add (m.this_parameter.name, m.this_parameter);
79 : }
80 573778 : if (!(m.return_type is VoidType) && m.get_postconditions ().size > 0) {
81 0 : m.result_var = new LocalVariable (m.return_type.copy (), "result", null, m.source_reference);
82 0 : m.result_var.is_result = true;
83 : }
84 :
85 573778 : base.add_method (m);
86 : }
87 :
88 : /**
89 : * Adds the specified property as a member to this interface.
90 : *
91 : * @param prop a property
92 : */
93 49301 : public override void add_property (Property prop) {
94 49301 : if (prop.field != null) {
95 0 : Report.error (prop.source_reference, "interface properties should be `abstract' or have `get' accessor and/or `set' mutator");
96 :
97 0 : prop.error = true;
98 0 : return;
99 : }
100 :
101 49301 : base.add_property (prop);
102 :
103 49301 : if (prop.binding != MemberBinding.STATIC) {
104 49301 : prop.this_parameter = new Parameter ("this", SemanticAnalyzer.get_this_type (prop, this), prop.source_reference);
105 49301 : prop.scope.add (prop.this_parameter.name, prop.this_parameter);
106 : }
107 : }
108 :
109 242 : public virtual List<Symbol> get_virtuals () {
110 242 : return virtuals;
111 : }
112 :
113 130835 : public override void accept (CodeVisitor visitor) {
114 130835 : visitor.visit_interface (this);
115 : }
116 :
117 127846 : public override void accept_children (CodeVisitor visitor) {
118 448558 : foreach (DataType type in prerequisites) {
119 160356 : type.accept (visitor);
120 : }
121 :
122 : // Invoke common implementation in ObjectTypeSymbol
123 127846 : base.accept_children (visitor);
124 : }
125 :
126 2152 : public override bool is_reference_type () {
127 2152 : return true;
128 : }
129 :
130 284240 : public override bool is_subtype_of (TypeSymbol t) {
131 284240 : if (this == t) {
132 189962 : return true;
133 : }
134 :
135 468738 : foreach (DataType prerequisite in prerequisites) {
136 281800 : if (prerequisite.type_symbol != null && prerequisite.type_symbol.is_subtype_of (t)) {
137 189140 : return true;
138 : }
139 : }
140 :
141 284240 : return false;
142 : }
143 :
144 68404 : public override void replace_type (DataType old_type, DataType new_type) {
145 86622 : for (int i = 0; i < prerequisites.size; i++) {
146 86622 : if (prerequisites[i] == old_type) {
147 68404 : prerequisites[i] = new_type;
148 68404 : new_type.parent_node = this;
149 68404 : return;
150 : }
151 : }
152 : }
153 :
154 1800080 : public override bool check (CodeContext context) {
155 1800080 : if (checked) {
156 1745843 : return !error;
157 : }
158 :
159 54237 : if (!base.check (context)) {
160 5 : return false;
161 : }
162 :
163 54237 : checked = true;
164 :
165 54237 : var old_source_file = context.analyzer.current_source_file;
166 107334 : var old_symbol = context.analyzer.current_symbol;
167 :
168 54237 : if (source_reference != null) {
169 54237 : context.analyzer.current_source_file = source_reference.file;
170 : }
171 54237 : context.analyzer.current_symbol = this;
172 :
173 190461 : foreach (DataType prerequisite_reference in get_prerequisites ()) {
174 : // check whether prerequisite is at least as accessible as the interface
175 68115 : if (!prerequisite_reference.is_accessible (this)) {
176 1 : error = true;
177 1 : Report.error (source_reference, "prerequisite `%s' is less accessible than interface `%s'", prerequisite_reference.to_string (), get_full_name ());
178 1 : return false;
179 : }
180 :
181 : // check whether there is the expected amount of type-arguments
182 68114 : if (!prerequisite_reference.check_type_arguments (context)) {
183 2 : error = true;
184 2 : return false;
185 : }
186 : }
187 :
188 : /* check prerequisites */
189 54234 : Class prereq_class = null;
190 122344 : foreach (DataType prereq in get_prerequisites ()) {
191 68112 : if (!(prereq is ObjectType)) {
192 1 : error = true;
193 1 : Report.error (source_reference, "Prerequisite `%s' of interface `%s' is not a class or interface", prereq.to_string (), get_full_name ());
194 1 : return false;
195 : }
196 :
197 : /* interfaces are not allowed to have multiple instantiable prerequisites */
198 68111 : if (prereq.type_symbol is Class) {
199 52754 : if (prereq_class != null) {
200 1 : error = true;
201 1 : Report.error (source_reference, "%s: Interfaces cannot have multiple instantiable prerequisites (`%s' and `%s')", get_full_name (), prereq.type_symbol.get_full_name (), prereq_class.get_full_name ());
202 1 : return false;
203 : }
204 :
205 120863 : prereq_class = (Class) prereq.type_symbol;
206 : }
207 : }
208 :
209 190450 : foreach (DataType type in prerequisites) {
210 68109 : type.check (context);
211 68109 : context.analyzer.check_type (type);
212 : }
213 :
214 54232 : foreach (Enum en in get_enums ()) {
215 0 : en.check (context);
216 : }
217 :
218 54234 : foreach (Field f in get_fields ()) {
219 1 : f.check (context);
220 : }
221 :
222 54232 : foreach (Constant c in get_constants ()) {
223 0 : c.check (context);
224 : }
225 :
226 54232 : if (context.abi_stability) {
227 820 : foreach (Symbol s in get_members ()) {
228 602 : if (s is Method) {
229 258 : var m = (Method) s;
230 258 : m.check (context);
231 258 : if (m.is_virtual || m.is_abstract) {
232 214 : virtuals.add (m);
233 : }
234 86 : } else if (s is Signal) {
235 0 : var sig = (Signal) s;
236 0 : sig.check (context);
237 0 : if (sig.is_virtual) {
238 0 : virtuals.add (sig);
239 : }
240 172 : } else if (s is Property) {
241 86 : var prop = (Property) s;
242 86 : prop.check (context);
243 86 : if (prop.is_virtual || prop.is_abstract) {
244 86 : virtuals.add (prop);
245 : }
246 : }
247 : }
248 : } else {
249 1115866 : foreach (Method m in get_methods ()) {
250 530883 : m.check (context);
251 530883 : if (m.is_virtual || m.is_abstract) {
252 348896 : virtuals.add (m);
253 : }
254 : }
255 :
256 121022 : foreach (Signal sig in get_signals ()) {
257 33461 : sig.check (context);
258 33461 : if (sig.is_virtual) {
259 31289 : virtuals.add (sig);
260 : }
261 : }
262 :
263 145232 : foreach (Property prop in get_properties ()) {
264 45566 : prop.check (context);
265 45566 : if (prop.is_virtual || prop.is_abstract) {
266 44636 : virtuals.add (prop);
267 : }
268 : }
269 : }
270 :
271 54236 : foreach (Class cl in get_classes ()) {
272 2 : cl.check (context);
273 : }
274 :
275 54236 : foreach (Interface iface in get_interfaces ()) {
276 2 : iface.check (context);
277 : }
278 :
279 54232 : foreach (Struct st in get_structs ()) {
280 0 : st.check (context);
281 : }
282 :
283 54232 : foreach (Delegate d in get_delegates ()) {
284 0 : d.check (context);
285 : }
286 :
287 54232 : Map<int, Symbol>? positions = new HashMap<int, Symbol> ();
288 54232 : bool ordered_seen = false;
289 54232 : bool unordered_seen = false;
290 904474 : foreach (Symbol sym in virtuals) {
291 425121 : int ordering = sym.get_attribute_integer ("CCode", "ordering", -1);
292 425121 : if (ordering < -1) {
293 0 : Report.error (sym.source_reference, "%s: Invalid ordering", sym.get_full_name ());
294 : // Mark state as invalid
295 0 : error = true;
296 0 : ordered_seen = true;
297 0 : unordered_seen = true;
298 0 : continue;
299 : }
300 425121 : bool ordered = ordering != -1;
301 425121 : if (ordered && unordered_seen && !ordered_seen) {
302 0 : Report.error (sym.source_reference, "%s: Cannot mix ordered and unordered virtuals", sym.get_full_name ());
303 0 : error = true;
304 : }
305 425121 : ordered_seen = ordered_seen || ordered;
306 425121 : if (!ordered && !unordered_seen && ordered_seen) {
307 0 : Report.error (sym.source_reference, "%s: Cannot mix ordered and unordered virtuals", sym.get_full_name ());
308 0 : error = true;
309 : }
310 425121 : unordered_seen = unordered_seen || !ordered;
311 425121 : if (!ordered_seen || !unordered_seen) {
312 425121 : if (ordered) {
313 0 : Symbol? prev = positions[ordering];
314 0 : if (prev != null) {
315 0 : Report.error (sym.source_reference, "%s: Duplicate ordering (previous virtual with the same position is %s)", sym.get_full_name (), prev.name);
316 0 : error = true;
317 : }
318 0 : positions[ordering] = sym;
319 : }
320 : }
321 : }
322 54232 : if (ordered_seen) {
323 0 : for (int i = 0; i < virtuals.size; i++) {
324 0 : Symbol? sym = positions[i];
325 0 : if (sym == null) {
326 0 : Report.error (source_reference, "%s: Gap in ordering in position %d", get_full_name (), i);
327 0 : error = true;
328 : }
329 0 : if (!error) {
330 0 : virtuals[i] = sym;
331 : }
332 : }
333 : }
334 :
335 54232 : context.analyzer.current_source_file = old_source_file;
336 54232 : context.analyzer.current_symbol = old_symbol;
337 :
338 54232 : return !error;
339 : }
340 : }
|