Line data Source code
1 : /* valaclass.vala
2 : *
3 : * Copyright (C) 2006-2012 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 a class declaration in the source code.
27 : */
28 750242 : public class Vala.Class : ObjectTypeSymbol {
29 : /**
30 : * Specifies the base class.
31 : */
32 3546756 : public Class base_class { get; set; }
33 :
34 : /**
35 : * Specifies whether this class is abstract. Abstract classes may not be
36 : * instantiated.
37 : */
38 68285 : public bool is_abstract { get; set; }
39 :
40 747473 : public bool is_partial { get; set; }
41 :
42 : /**
43 : * Specifies whether this class is sealed. Sealed classes may not be
44 : * sub-classed.
45 : */
46 59567 : public bool is_sealed { get; set; }
47 :
48 : /**
49 : * Instances of compact classes are fast to create and have a
50 : * compact memory layout. Compact classes don't support runtime
51 : * type information or virtual methods.
52 : */
53 : public bool is_compact {
54 2297588 : get {
55 2297588 : if (_is_compact == null) {
56 347332 : if (base_class != null && !base_class.is_subtype_of (this)) {
57 1537014 : _is_compact = base_class.is_compact;
58 : } else {
59 134266 : _is_compact = has_attribute ("Compact");
60 : }
61 : }
62 2297588 : return _is_compact;
63 : }
64 : }
65 :
66 : /**
67 : * Opaque compact classes hide their memory layout, only allowing private or
68 : * internal instance members.
69 : */
70 : public bool is_opaque {
71 426342 : get {
72 426342 : if (_is_opaque == null) {
73 71487 : _is_opaque = get_attribute_bool ("Compact", "opaque");
74 : }
75 426342 : return _is_opaque;
76 : }
77 : }
78 :
79 : /**
80 : * Instances of immutable classes are immutable after construction.
81 : */
82 : public bool is_immutable {
83 5225 : get {
84 5225 : if (_is_immutable == null) {
85 2355 : if (base_class != null && !base_class.is_subtype_of (this)) {
86 1272 : _is_immutable = base_class.is_immutable;
87 : } else {
88 1083 : _is_immutable = has_attribute ("Immutable");
89 : }
90 : }
91 5225 : return _is_immutable;
92 : }
93 : }
94 :
95 : /**
96 : * Instances of immutable classes are immutable after construction.
97 : */
98 : public bool is_singleton {
99 908095 : get {
100 908095 : if (_is_singleton == null) {
101 347333 : _is_singleton = has_attribute ("SingleInstance");
102 : }
103 908095 : return _is_singleton;
104 : }
105 : }
106 :
107 : /**
108 : * Specifies whether this class has private fields.
109 : */
110 7510 : public bool has_private_fields { get; set; }
111 :
112 : /**
113 : * Specifies whether this class has class fields.
114 : */
115 4099 : public bool has_class_private_fields { get; private set; }
116 :
117 374351 : private bool? _is_compact;
118 374351 : private bool? _is_opaque;
119 374351 : private bool? _is_immutable;
120 374351 : private bool? _is_singleton;
121 :
122 748704 : private List<DataType> base_types = new ArrayList<DataType> ();
123 748704 : private HashMap<Method,Method> implicit_implementations = new HashMap<Method,Method> (Symbol.hash_func, Symbol.equal_func);
124 :
125 : /**
126 : * Specifies the default construction method.
127 : */
128 1032378 : public CreationMethod? default_construction_method { get; private set; }
129 :
130 : /**
131 : * Specifies the instance constructor.
132 : */
133 : public Constructor? constructor {
134 1173123 : get { return _constructor; }
135 28 : private set {
136 56 : _constructor = value;
137 28 : if (_constructor != null) {
138 28 : _constructor.owner = scope;
139 : }
140 : }
141 : }
142 :
143 : /**
144 : * Specifies the class constructor.
145 : */
146 : public Constructor? class_constructor {
147 1175872 : get { return _class_constructor; }
148 10 : private set {
149 20 : _class_constructor = value;
150 10 : if (_class_constructor != null) {
151 10 : _class_constructor.owner = scope;
152 : }
153 : }
154 : }
155 :
156 : /**
157 : * Specifies the static class constructor.
158 : */
159 : public Constructor? static_constructor {
160 1172600 : get { return _static_constructor; }
161 9 : private set {
162 18 : _static_constructor = value;
163 9 : if (_static_constructor != null) {
164 9 : _static_constructor.owner = scope;
165 : }
166 : }
167 : }
168 :
169 : /**
170 : * Specifies the instance destructor.
171 : */
172 : public Destructor? destructor {
173 1174352 : get { return _destructor; }
174 18 : private set {
175 36 : _destructor = value;
176 18 : if (_destructor != null) {
177 18 : _destructor.owner = scope;
178 : }
179 : }
180 : }
181 :
182 : /**
183 : * Specifies the class destructor.
184 : */
185 : public Destructor? static_destructor {
186 1176659 : get { return _static_destructor; }
187 3 : private set {
188 6 : _static_destructor = value;
189 3 : if (_static_destructor != null) {
190 3 : _static_destructor.owner = scope;
191 : }
192 : }
193 : }
194 :
195 : /**
196 : * Specifies the class destructor.
197 : */
198 : public Destructor? class_destructor {
199 1174232 : get { return _class_destructor; }
200 5 : private set {
201 10 : _class_destructor = value;
202 5 : if (_class_destructor != null) {
203 5 : _class_destructor.owner = scope;
204 : }
205 : }
206 : }
207 :
208 : /**
209 : * Specifies whether this class denotes an error base.
210 : */
211 : public bool is_error_base {
212 7289962 : get {
213 7289962 : return has_attribute ("ErrorBase");
214 : }
215 : }
216 :
217 374351 : Constructor? _constructor;
218 374351 : Constructor? _class_constructor;
219 374351 : Constructor? _static_constructor;
220 374351 : Destructor? _destructor;
221 374351 : Destructor? _class_destructor;
222 374351 : Destructor? _static_destructor;
223 :
224 : /**
225 : * Creates a new class.
226 : *
227 : * @param name type name
228 : * @param source_reference reference to source code
229 : * @param comment class documentation
230 : * @return newly created class
231 : */
232 1123058 : public Class (string name, SourceReference? source_reference = null, Comment? comment = null) {
233 374353 : base (name, source_reference, comment);
234 : }
235 :
236 : /**
237 : * Adds the specified class or interface to the list of base types of
238 : * this class.
239 : *
240 : * @param type a class or interface reference
241 : */
242 338706 : public void add_base_type (DataType type) {
243 338706 : base_types.add (type);
244 338706 : type.parent_node = this;
245 : }
246 :
247 : /**
248 : * Returns the base type list.
249 : *
250 : * @return list of base types
251 : */
252 5962790 : public unowned List<DataType> get_base_types () {
253 5962790 : return base_types;
254 : }
255 :
256 : /**
257 : * Adds the specified field as a member to this class.
258 : *
259 : * @param f a field
260 : */
261 285576 : public override void add_field (Field f) {
262 285576 : base.add_field (f);
263 :
264 285576 : if (f.access == SymbolAccessibility.PRIVATE && f.binding == MemberBinding.INSTANCE) {
265 2578 : has_private_fields = true;
266 282998 : } else if (f.access == SymbolAccessibility.PRIVATE && f.binding == MemberBinding.CLASS) {
267 4 : has_class_private_fields = true;
268 : }
269 : }
270 :
271 : /**
272 : * Adds the specified method as a member to this class.
273 : *
274 : * @param m a method
275 : */
276 4159527 : public override void add_method (Method m) {
277 4159527 : if (m.binding != MemberBinding.STATIC || m is CreationMethod) {
278 3883260 : if (m.this_parameter != null) {
279 0 : m.scope.remove (m.this_parameter.name);
280 : }
281 3883260 : m.this_parameter = new Parameter ("this", SemanticAnalyzer.get_this_type (m, this), m.source_reference);
282 3883260 : m.scope.add (m.this_parameter.name, m.this_parameter);
283 : }
284 4159527 : if (!(m.return_type is VoidType) && m.get_postconditions ().size > 0) {
285 3 : if (m.result_var != null) {
286 0 : m.scope.remove (m.result_var.name);
287 : }
288 3 : m.result_var = new LocalVariable (m.return_type.copy (), "result", null, m.source_reference);
289 3 : m.result_var.is_result = true;
290 : }
291 4159527 : if (m is CreationMethod) {
292 537197 : if (m.name == null) {
293 316388 : default_construction_method = (CreationMethod) m;
294 316388 : m.name = ".new";
295 : }
296 :
297 537197 : unowned CreationMethod cm = (CreationMethod) m;
298 537197 : if (cm.class_name != null && cm.class_name != name) {
299 : // class_name is null for constructors generated by GIdlParser
300 1 : Report.error (m.source_reference, "missing return type in method `%s.%s´", get_full_name (), cm.class_name);
301 1 : m.error = true;
302 1 : return;
303 : }
304 537196 : if (is_abstract && cm.access == SymbolAccessibility.PUBLIC) {
305 : //TODO Report an error for external constructors too
306 1 : if (external_package) {
307 0 : Report.warning (m.source_reference, "Creation method of abstract class cannot be public.");
308 : } else {
309 1 : Report.error (m.source_reference, "Creation method of abstract class cannot be public.");
310 1 : error = true;
311 1 : return;
312 : }
313 : }
314 : }
315 :
316 4159525 : base.add_method (m);
317 : }
318 :
319 124 : public HashMap<Method,Method> get_implicit_implementations () {
320 124 : return implicit_implementations;
321 : }
322 :
323 : /**
324 : * Adds the specified property as a member to this class.
325 : *
326 : * @param prop a property
327 : */
328 400046 : public override void add_property (Property prop) {
329 400046 : base.add_property (prop);
330 :
331 400046 : if (prop.binding != MemberBinding.STATIC) {
332 400042 : prop.this_parameter = new Parameter ("this", SemanticAnalyzer.get_this_type (prop, this), prop.source_reference);
333 400042 : prop.scope.add (prop.this_parameter.name, prop.this_parameter);
334 : }
335 :
336 400046 : if (prop.field != null) {
337 496 : add_field (prop.field);
338 : }
339 : }
340 :
341 47 : public override void add_constructor (Constructor c) {
342 47 : switch (c.binding) {
343 : case MemberBinding.INSTANCE:
344 28 : if (constructor != null) {
345 1 : Report.error (c.source_reference, "class already contains a constructor");
346 : }
347 28 : constructor = c;
348 28 : break;
349 : case MemberBinding.CLASS:
350 10 : if (class_constructor != null) {
351 1 : Report.error (c.source_reference, "class already contains a class constructor");
352 : }
353 10 : class_constructor = c;
354 10 : break;
355 : case MemberBinding.STATIC:
356 9 : if (static_constructor != null) {
357 1 : Report.error (c.source_reference, "class already contains a static constructor");
358 : }
359 9 : static_constructor = c;
360 9 : break;
361 : default:
362 0 : assert_not_reached ();
363 : }
364 :
365 47 : if (c.binding != MemberBinding.STATIC) {
366 38 : if (c.this_parameter != null) {
367 0 : c.scope.remove (c.this_parameter.name);
368 : }
369 38 : c.this_parameter = new Parameter ("this", SemanticAnalyzer.get_this_type (c, this), c.source_reference);
370 38 : c.scope.add (c.this_parameter.name, c.this_parameter);
371 : }
372 : }
373 :
374 26 : public override void add_destructor (Destructor d) {
375 26 : switch (d.binding) {
376 : case MemberBinding.INSTANCE:
377 18 : if (destructor != null) {
378 1 : Report.error (d.source_reference, "class already contains a destructor");
379 : }
380 18 : destructor = d;
381 18 : break;
382 : case MemberBinding.CLASS:
383 5 : if (class_destructor != null) {
384 1 : Report.error (d.source_reference, "class already contains a class destructor");
385 : }
386 5 : class_destructor = d;
387 5 : break;
388 : case MemberBinding.STATIC:
389 3 : if (static_destructor != null) {
390 1 : Report.error (d.source_reference, "class already contains a static destructor");
391 : }
392 3 : static_destructor = d;
393 3 : break;
394 : default:
395 0 : assert_not_reached ();
396 : }
397 :
398 26 : if (d.binding != MemberBinding.STATIC) {
399 23 : if (d.this_parameter != null) {
400 0 : d.scope.remove (d.this_parameter.name);
401 : }
402 23 : d.this_parameter = new Parameter ("this", SemanticAnalyzer.get_this_type (d, this), d.source_reference);
403 23 : d.scope.add (d.this_parameter.name, d.this_parameter);
404 : }
405 : }
406 :
407 847705 : public override void accept (CodeVisitor visitor) {
408 847705 : visitor.visit_class (this);
409 : }
410 :
411 824357 : public override void accept_children (CodeVisitor visitor) {
412 2324833 : foreach (DataType type in base_types) {
413 750238 : type.accept (visitor);
414 : }
415 :
416 : // Invoke common implementation in ObjectTypeSymbol
417 824357 : base.accept_children (visitor);
418 :
419 824357 : if (constructor != null) {
420 83 : constructor.accept (visitor);
421 : }
422 :
423 824357 : if (class_constructor != null) {
424 29 : class_constructor.accept (visitor);
425 : }
426 :
427 824357 : if (static_constructor != null) {
428 28 : static_constructor.accept (visitor);
429 : }
430 :
431 824357 : if (destructor != null) {
432 52 : destructor.accept (visitor);
433 : }
434 :
435 824357 : if (static_destructor != null) {
436 4 : static_destructor.accept (visitor);
437 : }
438 :
439 824357 : if (class_destructor != null) {
440 12 : class_destructor.accept (visitor);
441 : }
442 : }
443 :
444 150042 : public override bool is_reference_type () {
445 150042 : return true;
446 : }
447 :
448 5015 : public bool is_fundamental () {
449 5015 : if (!is_compact && base_class == null) {
450 : return true;
451 : }
452 : return false;
453 : }
454 :
455 5589897 : public override bool is_subtype_of (TypeSymbol t) {
456 5589897 : if (this == t) {
457 3735478 : return true;
458 : }
459 :
460 4411824 : foreach (DataType base_type in base_types) {
461 4326038 : if (base_type.type_symbol != null && base_type.type_symbol != this
462 2140790 : && base_type.type_symbol.is_subtype_of (t)) {
463 1813091 : return true;
464 : }
465 : }
466 :
467 5589897 : return false;
468 : }
469 :
470 316346 : public override void replace_type (DataType old_type, DataType new_type) {
471 456846 : for (int i = 0; i < base_types.size; i++) {
472 456846 : if (base_types[i] == old_type) {
473 316346 : base_types[i] = new_type;
474 316346 : new_type.parent_node = this;
475 316346 : return;
476 : }
477 : }
478 : }
479 :
480 107389 : private void get_all_prerequisites (Interface iface, List<TypeSymbol> list) {
481 327797 : foreach (DataType prereq in iface.get_prerequisites ()) {
482 110204 : TypeSymbol type = prereq.type_symbol;
483 : /* skip on previous errors */
484 110204 : if (type == null) {
485 0 : continue;
486 : }
487 :
488 110204 : list.add (type);
489 110204 : if (type is Interface) {
490 5685 : get_all_prerequisites ((Interface) type, list);
491 :
492 : }
493 : }
494 : }
495 :
496 298949 : public bool is_a (ObjectTypeSymbol t) {
497 298949 : if (this == t) {
498 293264 : return true;
499 : }
500 :
501 208798 : foreach (DataType base_type in get_base_types ()) {
502 195929 : if (base_type.type_symbol is Class) {
503 188745 : if (((Class) base_type.type_symbol).is_a (t)) {
504 183062 : return true;
505 : }
506 7184 : } else if (base_type.type_symbol == t) {
507 5683 : return true;
508 : }
509 : }
510 :
511 298949 : return false;
512 : }
513 :
514 8 : public bool implements (Interface i) {
515 24 : foreach (DataType base_type in get_base_types ()) {
516 9 : if (base_type.type_symbol == i) {
517 1 : return true;
518 : }
519 : }
520 :
521 8 : return false;
522 : }
523 :
524 19504791 : public override bool check (CodeContext context) {
525 19504791 : if (checked) {
526 19157453 : return !error;
527 : }
528 :
529 347338 : if (!base.check (context)) {
530 9 : return false;
531 : }
532 :
533 347338 : checked = true;
534 :
535 347338 : var old_source_file = context.analyzer.current_source_file;
536 347338 : var old_symbol = context.analyzer.current_symbol;
537 :
538 347338 : if (source_reference != null) {
539 347338 : context.analyzer.current_source_file = source_reference.file;
540 : }
541 347338 : context.analyzer.current_symbol = this;
542 :
543 662431 : foreach (DataType base_type_reference in get_base_types ()) {
544 315098 : if (!base_type_reference.check (context)) {
545 2 : error = true;
546 2 : return false;
547 : }
548 :
549 315096 : if (!(base_type_reference is ObjectType)) {
550 1 : error = true;
551 1 : Report.error (source_reference, "base type `%s' of class `%s' is not an object type", base_type_reference.to_string (), get_full_name ());
552 1 : return false;
553 : }
554 :
555 : // check whether base type is at least as accessible as the class
556 315095 : if (!base_type_reference.is_accessible (this)) {
557 1 : error = true;
558 1 : Report.error (source_reference, "base type `%s' is less accessible than class `%s'", base_type_reference.to_string (), get_full_name ());
559 1 : return false;
560 : }
561 :
562 : // check whether there is the expected amount of type-arguments
563 315094 : if (!base_type_reference.check_type_arguments (context)) {
564 1 : error = true;
565 1 : return false;
566 : }
567 : }
568 :
569 977519 : foreach (DataType type in base_types) {
570 315093 : type.check (context);
571 315093 : context.analyzer.check_type (type);
572 : }
573 :
574 347333 : if (base_class != null && base_class.is_singleton) {
575 1 : error = true;
576 1 : Report.error (source_reference, "`%s' cannot inherit from SingleInstance class `%s'", get_full_name (), base_class.get_full_name ());
577 : }
578 :
579 347333 : if (is_singleton && !is_subtype_of (context.analyzer.object_type)) {
580 1 : error = true;
581 1 : Report.error (source_reference, "SingleInstance class `%s' requires inheritance from `GLib.Object'", get_full_name ());
582 : }
583 :
584 : /* singleton classes require an instance constructor */
585 347337 : if (is_singleton && constructor == null) {
586 4 : var c = new Constructor (source_reference);
587 4 : c.body = new Block (source_reference);
588 4 : add_constructor (c);
589 : }
590 :
591 347333 : if (!external_package && base_class != null && base_class.is_sealed) {
592 1 : error = true;
593 1 : Report.error (source_reference, "`%s' cannot inherit from sealed class `%s'", get_full_name (), base_class.get_full_name ());
594 : }
595 :
596 347333 : if (is_sealed) {
597 46859 : if (is_compact) {
598 1 : error = true;
599 1 : Report.error (source_reference, "Sealed class `%s' cannot be compact", get_full_name ());
600 1 : return false;
601 : }
602 46858 : if (is_abstract) {
603 1 : error = true;
604 1 : Report.error (source_reference, "Sealed class `%s' cannot be abstract", get_full_name ());
605 1 : return false;
606 : }
607 : }
608 :
609 347331 : if (base_class != null && !base_class.is_compact && has_attribute ("Compact")) {
610 1 : error = true;
611 1 : Report.error (source_reference, "Compact class `%s' cannot inherit from non-compact class `%s'", get_full_name (), base_class.get_full_name ());
612 1 : return false;
613 : }
614 :
615 : /* process enums first to avoid order problems in C code */
616 350242 : foreach (Enum en in get_enums ()) {
617 1456 : en.check (context);
618 : }
619 :
620 879224 : foreach (Field f in get_fields ()) {
621 265947 : if (is_compact && f.binding != MemberBinding.STATIC) {
622 : //FIXME Should external bindings follow this too?
623 135242 : if (!external_package && !is_opaque && f.access == SymbolAccessibility.PRIVATE) {
624 2 : Report.error (f.source_reference, "private fields are only supported in opaque compact classes, use [Compact (opaque = true)]");
625 2 : error = true;
626 : }
627 135242 : if (!external_package && is_opaque && (f.access == SymbolAccessibility.PUBLIC || f.access == SymbolAccessibility.PROTECTED)) {
628 1 : Report.error (f.source_reference, "fields in opaque compact classes must be private or internal");
629 1 : error = true;
630 : }
631 135242 : if (f.binding == MemberBinding.CLASS) {
632 2 : Report.error (f.source_reference, "class fields are not supported in compact classes");
633 2 : error = true;
634 : }
635 : }
636 :
637 265947 : f.check (context);
638 : }
639 :
640 431644 : foreach (Constant c in get_constants ()) {
641 42157 : c.check (context);
642 : }
643 :
644 8066762 : foreach (Method m in get_methods ()) {
645 3859716 : m.check (context);
646 : }
647 :
648 1092220 : foreach (Property prop in get_properties ()) {
649 372446 : if (prop.has_attribute ("NoAccessorMethod") && !is_subtype_of (context.analyzer.object_type)) {
650 1 : error = true;
651 1 : Report.error (prop.source_reference, "NoAccessorMethod is only allowed for properties in classes derived from GLib.Object");
652 1 : return false;
653 : }
654 372445 : prop.check (context);
655 : }
656 :
657 535129 : foreach (Signal sig in get_signals ()) {
658 93900 : sig.check (context);
659 : }
660 :
661 347329 : if (constructor != null) {
662 24 : constructor.check (context);
663 : }
664 :
665 347329 : if (class_constructor != null) {
666 8 : class_constructor.check (context);
667 : }
668 :
669 347329 : if (static_constructor != null) {
670 7 : static_constructor.check (context);
671 : }
672 :
673 347329 : if (destructor != null) {
674 13 : destructor.check (context);
675 : }
676 :
677 347329 : if (static_destructor != null) {
678 1 : static_destructor.check (context);
679 : }
680 :
681 347329 : if (class_destructor != null) {
682 3 : class_destructor.check (context);
683 : }
684 :
685 347369 : foreach (Class cl in get_classes ()) {
686 20 : cl.check (context);
687 : }
688 :
689 347333 : foreach (Interface iface in get_interfaces ()) {
690 2 : iface.check (context);
691 : }
692 :
693 347337 : foreach (Struct st in get_structs ()) {
694 4 : st.check (context);
695 : }
696 :
697 347371 : foreach (Delegate d in get_delegates ()) {
698 21 : d.check (context);
699 : }
700 :
701 : /* compact classes cannot implement interfaces */
702 347329 : if (is_compact) {
703 194423 : foreach (DataType base_type in get_base_types ()) {
704 22302 : if (base_type.type_symbol is Interface) {
705 1 : error = true;
706 1 : Report.error (source_reference, "compact classes `%s' may not implement interfaces", get_full_name ());
707 : }
708 : }
709 :
710 149819 : if (!external && !external_package && base_class != null && !base_class.is_subtype_of (context.analyzer.gsource_type)) {
711 15 : foreach (Field f in get_fields ()) {
712 1 : if (f.binding == MemberBinding.INSTANCE) {
713 1 : error = true;
714 1 : Report.error (source_reference, "derived compact classes may not have instance fields");
715 1 : break;
716 : }
717 : }
718 : }
719 : }
720 :
721 : /* gather all prerequisites */
722 347329 : List<TypeSymbol> prerequisites = new ArrayList<TypeSymbol> ();
723 977513 : foreach (DataType base_type in get_base_types ()) {
724 315092 : if (base_type.type_symbol is Interface) {
725 101704 : get_all_prerequisites ((Interface) base_type.type_symbol, prerequisites);
726 : }
727 : }
728 : /* check whether all prerequisites are met */
729 347329 : List<string> missing_prereqs = new ArrayList<string> (str_equal);
730 567737 : foreach (TypeSymbol prereq in prerequisites) {
731 110204 : if (!is_a ((ObjectTypeSymbol) prereq)) {
732 2 : missing_prereqs.insert (0, prereq.get_full_name ());
733 : }
734 : }
735 : /* report any missing prerequisites */
736 347330 : if (missing_prereqs.size > 0) {
737 1 : error = true;
738 :
739 1 : string error_string = "%s: some prerequisites (".printf (get_full_name ());
740 1 : bool first = true;
741 5 : foreach (string s in missing_prereqs) {
742 2 : if (first) {
743 1 : error_string = "%s`%s'".printf (error_string, s);
744 : first = false;
745 : } else {
746 1 : error_string = "%s, `%s'".printf (error_string, s);
747 : }
748 : }
749 1 : error_string += ") are not met";
750 1 : Report.error (source_reference, error_string);
751 : }
752 :
753 : /* VAPI classes don't have to specify overridden methods */
754 347329 : if (source_type == SourceFileType.SOURCE) {
755 : /* all abstract symbols defined in base types have to be at least defined (or implemented) also in this type */
756 2680 : foreach (DataType base_type in get_base_types ()) {
757 787 : if (base_type.type_symbol is Interface) {
758 146 : unowned Interface iface = (Interface) base_type.type_symbol;
759 :
760 146 : if (base_class != null && base_class.is_subtype_of (iface)) {
761 : // reimplementation of interface, class is not required to reimplement all methods
762 3 : break;
763 : }
764 :
765 : /* We do not need to do expensive equality checking here since this is done
766 : * already. We only need to guarantee the symbols are present.
767 : */
768 :
769 : /* check methods */
770 415 : foreach (Method m in iface.get_methods ()) {
771 136 : if (m.is_abstract) {
772 : var implemented = false;
773 : unowned Class? base_class = this;
774 203 : while (base_class != null && !implemented) {
775 1370 : foreach (var impl in base_class.get_methods ()) {
776 725 : if (impl.base_interface_method == m || (base_class != this
777 298 : && impl.base_interface_method == null && impl.name == m.name
778 3 : && (impl.base_interface_type == null || impl.base_interface_type.type_symbol == iface)
779 3 : && impl.compatible_no_error (m))) {
780 : // method is used as interface implementation, so it is not unused
781 90 : impl.version.check (context, source_reference);
782 90 : impl.used = true;
783 90 : implemented = true;
784 90 : if (impl.base_interface_method == null) {
785 2 : implicit_implementations.set (m, impl);
786 : }
787 90 : break;
788 : }
789 : }
790 106 : base_class = base_class.base_class;
791 : }
792 97 : if (!implemented) {
793 7 : error = true;
794 7 : Report.error (source_reference, "`%s' does not implement interface method `%s'", get_full_name (), m.get_full_name ());
795 : }
796 : }
797 : }
798 :
799 : /* check properties */
800 229 : foreach (Property prop in iface.get_properties ()) {
801 84 : if (prop.is_abstract) {
802 : Symbol sym = null;
803 : unowned Class? base_class = this;
804 85 : while (base_class != null && !(sym is Property)) {
805 44 : sym = base_class.scope.lookup (prop.name);
806 44 : base_class = base_class.base_class;
807 : }
808 81 : if (sym is Property) {
809 40 : var base_prop = (Property) sym;
810 40 : string? invalid_match = null;
811 : // No check at all for "new" classified properties, really?
812 40 : if (!base_prop.hides && !base_prop.compatible (prop, out invalid_match)) {
813 4 : error = true;
814 4 : Report.error (source_reference, "Type and/or accessors of inherited properties `%s' and `%s' do not match: %s.", prop.get_full_name (), base_prop.get_full_name (), invalid_match);
815 : }
816 : // property is used as interface implementation, so it is not unused
817 40 : sym.version.check (context, source_reference);
818 40 : sym.used = true;
819 : } else {
820 1 : error = true;
821 1 : Report.error (source_reference, "`%s' does not implement interface property `%s'", get_full_name (), prop.get_full_name ());
822 : }
823 : }
824 : }
825 : }
826 : }
827 :
828 : /* all abstract symbols defined in base classes have to be implemented in non-abstract classes */
829 1112 : if (!is_abstract) {
830 1050 : unowned Class? base_class = base_class;
831 1303 : while (base_class != null && base_class.is_abstract) {
832 5713 : foreach (Method base_method in base_class.get_methods ()) {
833 3017 : if (base_method.is_abstract) {
834 287 : var override_method = SemanticAnalyzer.symbol_lookup_inherited (this, base_method.name) as Method;
835 287 : if (override_method == null || !override_method.overrides) {
836 1 : error = true;
837 1 : Report.error (source_reference, "`%s' does not implement abstract method `%s'", get_full_name (), base_method.get_full_name ());
838 : }
839 : }
840 : }
841 1177 : foreach (Property base_property in base_class.get_properties ()) {
842 491 : if (base_property.is_abstract) {
843 29 : var override_property = SemanticAnalyzer.symbol_lookup_inherited (this, base_property.name) as Property;
844 29 : if (override_property == null || !override_property.overrides) {
845 1 : error = true;
846 1 : Report.error (source_reference, "`%s' does not implement abstract property `%s'", get_full_name (), base_property.get_full_name ());
847 : }
848 : }
849 : }
850 253 : base_class = base_class.base_class;
851 : }
852 : }
853 : }
854 :
855 347329 : context.analyzer.current_source_file = old_source_file;
856 347329 : context.analyzer.current_symbol = old_symbol;
857 :
858 347329 : return !error;
859 : }
860 : }
861 :
862 : // vim:sw=8 noet
|