3 * Copyright (C) 2006-2010 Jürg Billeter
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.
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.
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
20 * Jürg Billeter <j@bitron.ch>
26 * Represents a class declaration in the source code.
28 public class Vala
.Interface
: ObjectTypeSymbol
{
29 private List
<DataType
> prerequisites
= new ArrayList
<DataType
> ();
31 private List
<Symbol
> virtuals
= new ArrayList
<Symbol
> ();
34 * Creates a new interface.
36 * @param name type name
37 * @param source_reference reference to source code
38 * @return newly created interface
40 public Interface (string name
, SourceReference? source_reference
= null, Comment? comment
= null) {
41 base (name
, source_reference
, comment
);
45 * Adds the specified interface or class to the list of prerequisites of
48 * @param type an interface or class reference
50 public void add_prerequisite (DataType type
) {
51 prerequisites
.add (type
);
52 type
.parent_node
= this
;
56 * Returns a copy of the base type list.
58 * @return list of base types
60 public List
<DataType
> get_prerequisites () {
65 * Adds the specified method as a member to this interface.
69 public override void add_method (Method m
) {
70 if (m is CreationMethod
) {
71 Report
.error (m
.source_reference
, "construction methods may only be declared within classes and structs");
76 if (m
.binding
== MemberBinding
.INSTANCE
) {
77 m
.this_parameter
= new
Parameter ("this", get_this_type ());
78 m
.scope
.add (m
.this_parameter
.name
, m
.this_parameter
);
80 if (!(m
.return_type is VoidType
) && m
.get_postconditions ().size
> 0) {
81 m
.result_var
= new
LocalVariable (m
.return_type
.copy (), "result", null, source_reference
);
82 m
.result_var
.is_result
= true;
89 * Adds the specified property as a member to this interface.
91 * @param prop a property
93 public override void add_property (Property prop
) {
94 if (prop
.field
!= null) {
95 Report
.error (prop
.source_reference
, "automatic properties are not allowed in interfaces");
101 base.add_property (prop
);
103 prop
.this_parameter
= new
Parameter ("this", new
ObjectType (this
));
104 prop
.scope
.add (prop
.this_parameter
.name
, prop
.this_parameter
);
107 public virtual List
<Symbol
> get_virtuals () {
111 public override void accept (CodeVisitor visitor
) {
112 visitor
.visit_interface (this
);
115 public override void accept_children (CodeVisitor visitor
) {
116 foreach (DataType type
in prerequisites
) {
117 type
.accept (visitor
);
120 foreach (TypeParameter p
in get_type_parameters ()) {
124 /* process enums first to avoid order problems in C code */
125 foreach (Enum en
in get_enums ()) {
129 foreach (Method m
in get_methods ()) {
133 foreach (Field f
in get_fields ()) {
137 foreach (Constant c
in get_constants ()) {
141 foreach (Property prop
in get_properties ()) {
142 prop
.accept (visitor
);
145 foreach (Signal sig
in get_signals ()) {
146 sig
.accept (visitor
);
149 foreach (Class cl
in get_classes ()) {
153 foreach (Struct st
in get_structs ()) {
157 foreach (Delegate d
in get_delegates ()) {
162 public override bool is_reference_type () {
166 public override bool is_subtype_of (TypeSymbol t
) {
171 foreach (DataType prerequisite
in prerequisites
) {
172 if (prerequisite
.data_type
!= null && prerequisite
.data_type
.is_subtype_of (t
)) {
180 public override void replace_type (DataType old_type
, DataType new_type
) {
181 for (int i
= 0; i
< prerequisites
.size
; i
++) {
182 if (prerequisites
[i
] == old_type
) {
183 prerequisites
[i
] = new_type
;
184 new_type
.parent_node
= this
;
190 public override bool check (CodeContext context
) {
197 var old_source_file
= context
.analyzer
.current_source_file
;
198 var old_symbol
= context
.analyzer
.current_symbol
;
200 if (source_reference
!= null) {
201 context
.analyzer
.current_source_file
= source_reference
.file
;
203 context
.analyzer
.current_symbol
= this
;
205 foreach (DataType prerequisite_reference
in get_prerequisites ()) {
206 // check whether prerequisite is at least as accessible as the interface
207 if (!context
.analyzer
.is_type_accessible (this
, prerequisite_reference
)) {
209 Report
.error (source_reference
, "prerequisite `%s` is less accessible than interface `%s`".printf (prerequisite_reference
.to_string (), get_full_name ()));
214 /* check prerequisites */
215 Class prereq_class
= null;
216 foreach (DataType prereq
in get_prerequisites ()) {
217 TypeSymbol class_or_interface
= prereq
.data_type
;
218 /* skip on previous errors */
219 if (class_or_interface
== null) {
224 if (!(class_or_interface is ObjectTypeSymbol
)) {
226 Report
.error (source_reference
, "Prerequisite `%s` of interface `%s` is not a class or interface".printf (get_full_name (), class_or_interface
.to_string ()));
230 /* interfaces are not allowed to have multiple instantiable prerequisites */
231 if (class_or_interface is Class
) {
232 if (prereq_class
!= null) {
234 Report
.error (source_reference
, "%s: Interfaces cannot have multiple instantiable prerequisites (`%s' and `%s')".printf (get_full_name (), class_or_interface
.get_full_name (), prereq_class
.get_full_name ()));
238 prereq_class
= (Class
) class_or_interface
;
242 foreach (DataType type
in prerequisites
) {
243 type
.check (context
);
246 foreach (TypeParameter p
in get_type_parameters ()) {
250 foreach (Enum en
in get_enums ()) {
254 foreach (Field f
in get_fields ()) {
258 foreach (Constant c
in get_constants ()) {
262 if (context
.abi_stability
) {
263 foreach (Symbol s
in get_members ()) {
267 if (m
.is_virtual
|| m
.is_abstract
) {
270 } else if (s is Signal
) {
271 var sig
= (Signal
) s
;
273 if (sig
.is_virtual
) {
276 } else if (s is Property
) {
277 var prop
= (Property
) s
;
278 prop
.check (context
);
279 if (prop
.is_virtual
|| prop
.is_abstract
) {
285 foreach (Method m
in get_methods ()) {
287 if (m
.is_virtual
|| m
.is_abstract
) {
292 foreach (Signal sig
in get_signals ()) {
294 if (sig
.is_virtual
) {
299 foreach (Property prop
in get_properties ()) {
300 prop
.check (context
);
301 if (prop
.is_virtual
|| prop
.is_abstract
) {
307 foreach (Class cl
in get_classes ()) {
311 foreach (Struct st
in get_structs ()) {
315 foreach (Delegate d
in get_delegates ()) {
319 Map
<int, Symbol
>? positions
= new HashMap
<int, Symbol
> ();
320 bool ordered_seen
= false;
321 bool unordered_seen
= false;
322 foreach (Symbol sym
in virtuals
) {
323 int ordering
= sym
.get_attribute_integer ("CCode", "ordering", -1);
325 Report
.error (sym
.source_reference
, "%s: Invalid ordering".printf (sym
.get_full_name ()));
326 // Mark state as invalid
329 unordered_seen
= true;
332 bool ordered
= ordering
!= -1;
333 if (ordered
&& unordered_seen
&& !ordered_seen
) {
334 Report
.error (sym
.source_reference
, "%s: Cannot mix ordered and unordered virtuals".printf (sym
.get_full_name ()));
337 ordered_seen
= ordered_seen
|| ordered
;
338 if (!ordered
&& !unordered_seen
&& ordered_seen
) {
339 Report
.error (sym
.source_reference
, "%s: Cannot mix ordered and unordered virtuals".printf (sym
.get_full_name ()));
342 unordered_seen
= unordered_seen
|| !ordered
;
343 if (!ordered_seen
|| !unordered_seen
) {
345 Symbol? prev
= positions
[ordering
];
347 Report
.error (sym
.source_reference
, "%s: Duplicate ordering (previous virtual with the same position is %s)".printf (sym
.get_full_name (), prev
.name
));
350 positions
[ordering
] = sym
;
355 for (int i
= 0; i
< virtuals
.size
; i
++) {
356 Symbol? sym
= positions
[i
];
358 Report
.error (source_reference
, "%s: Gap in ordering in position %d".printf (get_full_name (), i
));
367 context
.analyzer
.current_source_file
= old_source_file
;
368 context
.analyzer
.current_symbol
= old_symbol
;