efl

Форк
0
/
database_validate.c 
1766 строк · 56.3 Кб
1
#include <ctype.h>
2
#include <assert.h>
3
#include <stdlib.h>
4

5
#ifdef HAVE_CONFIG_H
6
# include "config.h"
7
#endif
8

9
#include "eo_lexer.h"
10
#include "eolian_priv.h"
11

12
typedef struct _Validate_State
13
{
14
   Eina_Bool warned;
15
   Eina_Bool stable;
16
   Eina_Bool in_tree;
17
   Eina_Bool unimplemented_beta;
18
   const char *since_ver;
19
} Validate_State;
20

21
static Eina_Bool
22
_set_stable(Validate_State *vals, Eina_Bool newval)
23
{
24
   Eina_Bool ret = vals->stable;
25
   vals->stable = newval;
26
   return ret;
27
}
28

29
static Eina_Bool
30
_reset_stable(Validate_State *vals, Eina_Bool oldval, Eina_Bool ret)
31
{
32
   vals->stable = oldval;
33
   return ret;
34
}
35

36
static Eina_Bool
37
_validate(Eolian_Object *obj)
38
{
39
   obj->validated = EINA_TRUE;
40
   return EINA_TRUE;
41
}
42

43
#define _eo_parser_log(_base, ...) \
44
   eolian_state_log_obj((_base)->unit->state, (_base), __VA_ARGS__)
45

46
static Eina_Bool
47
_validate_docstr(Eina_Stringshare *str, const Eolian_Object *info, Eina_List **rdbg)
48
{
49
   if (!str || !str[0]) return EINA_TRUE;
50

51
   Eina_Bool ret = EINA_TRUE;
52
   Eina_List *pl = eolian_documentation_string_split(str);
53
   char *par;
54
   EINA_LIST_FREE(pl, par)
55
     {
56
        const char *doc = par;
57
        Eolian_Doc_Token tok;
58
        eolian_doc_token_init(&tok);
59
        while (ret && (doc = eolian_documentation_tokenize(doc, &tok)))
60
          {
61
             if (eolian_doc_token_type_get(&tok) == EOLIAN_DOC_TOKEN_REF)
62
               {
63
                  /* check staging first, then main */
64
                  Eolian_Object_Type tp = database_doc_token_ref_resolve(&tok,
65
                    &info->unit->state->staging.unit,
66
                    &info->unit->state->main.unit,
67
                    NULL, NULL);
68
                  if (tp == EOLIAN_OBJECT_UNKNOWN)
69
                    {
70
                       size_t dbgn = (size_t)eina_list_data_get(*rdbg);
71
                       char *refn = eolian_doc_token_text_get(&tok);
72
                       Eolian_Object tmp;
73
                       memset(&tmp, 0, sizeof(Eolian_Object));
74
                       tmp.unit = info->unit;
75
                       tmp.file = info->file;
76
                       tmp.line = (int)(dbgn & 0xFFFFF);
77
                       tmp.column = (int)(dbgn >> 20);
78
                       eolian_state_log_obj(info->unit->state, &tmp,
79
                                            "failed validating reference '%s'", refn);
80
                       free(refn);
81
                       ret = EINA_FALSE;
82
                       break;
83
                    }
84
                  *rdbg = eina_list_next(*rdbg);
85
               }
86
          }
87
        free(par);
88
     }
89

90
   return ret;
91
}
92

93
static Eina_Bool
94
_validate_doc_since(Validate_State *vals, Eolian_Documentation *doc)
95
{
96
   if (!doc || !vals->stable)
97
     return EINA_TRUE;
98

99
   if (doc->since)
100
     {
101
        if (!doc->since[0])
102
          {
103
             /* this should not really happen */
104
             _eo_parser_log(&doc->base, "empty @since tag");
105
             return EINA_FALSE;
106
          }
107
        /* this is EFL; check the numbers */
108
        if (vals->in_tree)
109
          {
110
             const char *snum = doc->since;
111
             if (strncmp(snum, "1.", 2))
112
               {
113
                  _eo_parser_log(&doc->base, "invalid EFL version in @since");
114
                  return EINA_FALSE;
115
               }
116
             snum += 2;
117
             unsigned long min = strtoul(snum, NULL, 10);
118
             if (min < 22)
119
               {
120
                  _eo_parser_log(&doc->base, "stable APIs must be 1.22 or higher");
121
                  return EINA_FALSE;
122
               }
123
          }
124
        vals->since_ver = doc->since;
125
     }
126
   else if (!vals->since_ver)
127
     {
128
        _eo_parser_log(&doc->base, "missing @since tag");
129
        return EINA_FALSE;
130
     }
131

132
   return EINA_TRUE;
133
}
134

135
static Eina_Bool
136
_validate_doc_since_reset(Validate_State *vals, Eolian_Documentation *doc)
137
{
138
   if (!doc || !doc->since)
139
     return EINA_TRUE;
140

141
   const char *old_since = vals->since_ver;
142
   Eina_Bool ret = _validate_doc_since(vals, doc);
143
   vals->since_ver = old_since;
144
   return ret;
145
}
146

147
static Eina_Bool
148
_validate_doc(Eolian_Documentation *doc)
149
{
150
   if (!doc)
151
     return EINA_TRUE;
152

153
   Eina_List *rdbg = doc->ref_dbg;
154

155
   if (!_validate_docstr(doc->summary, &doc->base, &rdbg))
156
     return EINA_FALSE;
157
   if (!_validate_docstr(doc->description, &doc->base, &rdbg))
158
     return EINA_FALSE;
159

160
   return _validate(&doc->base);
161
}
162

163
static Eina_Bool _validate_type(Validate_State *vals, Eolian_Type *tp,
164
                                Eina_Bool by_ref, Eina_Bool is_ret);
165
static Eina_Bool _validate_type_by_ref(Validate_State *vals, Eolian_Type *tp,
166
                                       Eina_Bool by_ref, Eina_Bool move,
167
                                       Eina_Bool is_ret);
168
static Eina_Bool _validate_expr(Eolian_Expression *expr,
169
                                const Eolian_Type *tp,
170
                                Eolian_Expression_Mask msk,
171
                                Eina_Bool by_ref);
172
static Eina_Bool _validate_function(Validate_State *vals,
173
                                    Eolian_Function *func,
174
                                    Eina_Hash *nhash);
175

176
typedef struct _Cb_Ret
177
{
178
   Validate_State *vals;
179
   Eina_Bool succ;
180
} Cb_Ret;
181

182
static Eina_Bool
183
_sf_map_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED,
184
           const Eolian_Struct_Type_Field *sf, Cb_Ret *sc)
185
{
186
   sc->succ = _validate_type_by_ref(sc->vals, sf->type, sf->by_ref,
187
                                    sf->move, EINA_FALSE);
188

189
   if (!sc->succ)
190
     return EINA_FALSE;
191

192
   sc->succ = _validate_doc(sf->doc);
193
   if (sc->succ) sc->succ = _validate_doc_since_reset(sc->vals, sf->doc);
194

195
   return sc->succ;
196
}
197

198
static Eina_Bool
199
_ef_map_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED,
200
           const Eolian_Enum_Type_Field *ef, Cb_Ret *sc)
201
{
202
   if (ef->value)
203
     sc->succ = _validate_expr(ef->value, NULL, EOLIAN_MASK_INT, EINA_FALSE);
204
   else
205
     sc->succ = EINA_TRUE;
206

207
   if (!sc->succ)
208
     return EINA_FALSE;
209

210
   sc->succ = _validate_doc(ef->doc);
211
   if (sc->succ) sc->succ = _validate_doc_since_reset(sc->vals, ef->doc);
212

213
   return sc->succ;
214
}
215

216
static Eina_Bool
217
_validate_typedecl(Validate_State *vals, Eolian_Typedecl *tp)
218
{
219
   if (tp->base.validated)
220
     return EINA_TRUE;
221

222
   const char *old_since = vals->since_ver;
223
   vals->since_ver = NULL;
224

225
   /* for the time being assume all typedecls are beta unless overridden */
226
   Eina_Bool was_stable = _set_stable(vals, !tp->base.is_beta);
227

228
   if (!_validate_doc(tp->doc))
229
     return EINA_FALSE;
230

231
   if (!_validate_doc_since(vals, tp->doc))
232
     return EINA_FALSE;
233

234
   switch (tp->type)
235
     {
236
      case EOLIAN_TYPEDECL_ALIAS:
237
        if (!_validate_type(vals, tp->base_type, EINA_FALSE, EINA_FALSE))
238
          return _reset_stable(vals, was_stable, EINA_FALSE);
239
        if (tp->base_type->ownable)
240
          tp->ownable = EINA_TRUE;
241
        _reset_stable(vals, was_stable, EINA_TRUE);
242
        vals->since_ver = old_since;
243
        return _validate(&tp->base);
244
      case EOLIAN_TYPEDECL_STRUCT:
245
        {
246
           Cb_Ret rt = { vals, EINA_TRUE };
247
           eina_hash_foreach(tp->fields, (Eina_Hash_Foreach)_sf_map_cb, &rt);
248
           if (!rt.succ)
249
             return _reset_stable(vals, was_stable, EINA_FALSE);
250
           _reset_stable(vals, was_stable, EINA_TRUE);
251
           vals->since_ver = old_since;
252
           return _validate(&tp->base);
253
        }
254
      case EOLIAN_TYPEDECL_STRUCT_OPAQUE:
255
        _reset_stable(vals, was_stable, EINA_TRUE);
256
        vals->since_ver = old_since;
257
        return _validate(&tp->base);
258
      case EOLIAN_TYPEDECL_ENUM:
259
        {
260
           if (vals->stable && tp->legacy)
261
             {
262
                _eo_parser_log(&tp->base, "legacy field not allowed in stable enums");
263
                return EINA_FALSE;
264
             }
265
           Cb_Ret rt = { vals, EINA_TRUE };
266
           eina_hash_foreach(tp->fields, (Eina_Hash_Foreach)_ef_map_cb, &rt);
267
           if (!rt.succ)
268
             return _reset_stable(vals, was_stable, EINA_FALSE);
269
           _reset_stable(vals, was_stable, EINA_TRUE);
270
           vals->since_ver = old_since;
271
           return _validate(&tp->base);
272
        }
273
      case EOLIAN_TYPEDECL_FUNCTION_POINTER:
274
        if (!_validate_function(vals, tp->function_pointer, NULL))
275
          return _reset_stable(vals, was_stable, EINA_FALSE);
276
        _reset_stable(vals, was_stable, EINA_TRUE);
277
        vals->since_ver = old_since;
278
        return _validate(&tp->base);
279
      default:
280
        return _reset_stable(vals, was_stable, EINA_FALSE);
281
     }
282

283
   //Unexpected case?
284
   return EINA_FALSE;
285
}
286

287
static Eina_Bool
288
_validate_by_ref(Validate_State *vals, Eolian_Type *tp, Eina_Bool by_ref,
289
                 Eina_Bool move)
290
{
291
   Eina_Bool maybe_ownable =
292
     database_type_is_ownable(tp->base.unit, tp, EINA_FALSE, NULL);
293

294
   /* only allow value types when @by_ref */
295
   if (by_ref && maybe_ownable)
296
     {
297
        _eo_parser_log(&tp->base, "@by_ref is only allowed for value types");
298
        return EINA_FALSE;
299
     }
300

301
   /* futures can be whatever... */
302
   if (tp->btype == EOLIAN_TYPE_BUILTIN_FUTURE)
303
     return EINA_TRUE;
304

305
   if (tp->tdecl && (tp->tdecl->type == EOLIAN_TYPEDECL_STRUCT_OPAQUE))
306
     {
307
        if (vals->stable && !maybe_ownable && !by_ref)
308
          {
309
             _eo_parser_log(&tp->base, "opaque structs must be by reference");
310
             return EINA_FALSE;
311
          }
312
     }
313

314
   /* not marked @move, or marked @by_ref; just validate */
315
   if (!move || by_ref)
316
      return EINA_TRUE;
317

318
   /* marked @move, not pointer-like or otherwise ownable, error */
319
   if (!maybe_ownable || !tp->ownable)
320
     {
321
        _eo_parser_log(&tp->base, "type '%s' is not ownable", tp->base.name);
322
        return EINA_FALSE;
323
     }
324

325
   return EINA_TRUE;
326
}
327

328
static Eina_Bool
329
_validate_type_by_ref(Validate_State *vals, Eolian_Type *tp,
330
                      Eina_Bool by_ref, Eina_Bool move, Eina_Bool is_ret)
331
{
332
   if (!_validate_type(vals, tp, by_ref, is_ret))
333
     return EINA_FALSE;
334

335
   return _validate_by_ref(vals, tp, by_ref, move);
336
}
337

338
static Eina_Bool
339
_validate_type(Validate_State *vals, Eolian_Type *tp, Eina_Bool by_ref,
340
               Eina_Bool is_ret)
341
{
342
   const Eolian_Unit *src = tp->base.unit;
343

344
   if (tp->is_ptr)
345
     {
346
        if (vals->stable)
347
          {
348
             _eo_parser_log(&tp->base, "ptr() used in stable API");
349
             return EINA_FALSE;
350
          }
351
        tp->is_ptr = EINA_FALSE;
352
        Eina_Bool still_ownable = database_type_is_ownable(src, tp, EINA_FALSE, NULL);
353
        tp->is_ptr = EINA_TRUE;
354
        if (still_ownable)
355
          {
356
             _eo_parser_log(&tp->base, "cannot take a pointer to pointer type");
357
             return EINA_FALSE;
358
          }
359
     }
360

361
   if (tp->is_const && !tp->is_ptr)
362
     {
363
        if (database_type_is_ownable(src, tp, EINA_FALSE, NULL))
364
          {
365
             int kw = eo_lexer_keyword_str_to_id(tp->base.name);
366
             switch (kw)
367
               {
368
                case KW_string:
369
                case KW_mstring:
370
                case KW_stringshare:
371
                  _eo_parser_log(&tp->base, "spurious explicit const on string type");
372
                  return EINA_FALSE;
373
                default:
374
                  {
375
                     if (!is_ret)
376
                       break;
377
                     const char *ct = eo_lexer_get_c_type(kw);
378
                     if (ct && ct[strlen(ct) - 1] != '*')
379
                       {
380
                          _eo_parser_log(&tp->base, "return const requires a C pointer");
381
                          return EINA_FALSE;
382
                       }
383
                  }
384
               }
385
            }
386
        else if (!by_ref && is_ret)
387
          {
388
             _eo_parser_log(&tp->base, "value returns cannot be const");
389
             return EINA_FALSE;
390
          }
391
     }
392

393
   switch (tp->type)
394
     {
395
      case EOLIAN_TYPE_VOID:
396
        return _validate(&tp->base);
397
      case EOLIAN_TYPE_UNDEFINED:
398
        if (vals->stable)
399
          {
400
             _eo_parser_log(&tp->base,
401
               "__undefined_type not allowed in stable context");
402
             return EINA_FALSE;
403
          }
404
        return _validate(&tp->base);
405
      case EOLIAN_TYPE_REGULAR:
406
        {
407
           if (tp->base_type)
408
             {
409
                int kwid = eo_lexer_keyword_str_to_id(tp->base.name);
410
                if (kwid > KW_void)
411
                  tp->ownable = EINA_TRUE;
412
                if ((kwid == KW_hash || kwid == KW_list) && vals->stable)
413
                  {
414
                     _eo_parser_log(&tp->base, "hashes and lists not allowed in stable context");
415
                     return EINA_FALSE;
416
                  }
417
                Eolian_Type *itp = tp->base_type;
418
                /* validate types in brackets so transitive fields get written */
419
                while (itp)
420
                  {
421
                     if (vals->stable && itp->is_ptr)
422
                       {
423
                          _eo_parser_log(&itp->base,
424
                                         "pointer types not allowed in '%s' in stable context",
425
                                         tp->base.name);
426
                          return EINA_FALSE;
427
                       }
428
                     if (!_validate_type_by_ref(vals, itp, EINA_FALSE, itp->move, EINA_FALSE))
429
                       return EINA_FALSE;
430
                     itp = itp->next_type;
431
                  }
432
                return _validate(&tp->base);
433
             }
434
           /* builtins */
435
           int id = eo_lexer_keyword_str_to_id(tp->base.name);
436
           if (id)
437
             {
438
                if (!eo_lexer_is_type_keyword(id))
439
                  return EINA_FALSE;
440
                switch (id)
441
                  {
442
                   case KW_mstring:
443
                   case KW_stringshare:
444
                   case KW_any_value:
445
                   case KW_any_value_ref:
446
                   case KW_binbuf:
447
                   case KW_strbuf:
448
                     tp->ownable = EINA_TRUE;
449
                     break;
450
                   default:
451
                     break;
452
                  }
453
                if (id == KW_void_ptr && vals->stable)
454
                  {
455
                     _eo_parser_log(&tp->base,
456
                       "void pointers not allowed in stable context");
457
                     return EINA_FALSE;
458
                  }
459
                return _validate(&tp->base);
460
             }
461
           /* user defined */
462
           tp->tdecl = database_type_decl_find(src, tp);
463
           if (!tp->tdecl)
464
             {
465
                _eo_parser_log(&tp->base, "undefined type %s", tp->base.name);
466
                return EINA_FALSE;
467
             }
468
           else if (vals->stable && tp->tdecl->base.is_beta)
469
             {
470
                /* we should enable this by default, but can't for now */
471
                _eo_parser_log(&tp->base, "beta type declaration '%s' used in stable context",
472
                               tp->tdecl->base.name);
473
                return EINA_FALSE;
474
             }
475
           if (!_validate_typedecl(vals, tp->tdecl))
476
             return EINA_FALSE;
477
           if (tp->tdecl->ownable)
478
             tp->ownable = EINA_TRUE;
479
           tp->base.c_name = eina_stringshare_ref(tp->tdecl->base.c_name);
480
           return _validate(&tp->base);
481
        }
482
      case EOLIAN_TYPE_CLASS:
483
        {
484
           tp->klass = (Eolian_Class *)eolian_unit_class_by_name_get(src, tp->base.name);
485
           if (!tp->klass)
486
             {
487
                _eo_parser_log(&tp->base, "undefined class %s "
488
                         "(likely wrong namespacing)", tp->base.name);
489
                return EINA_FALSE;
490
             }
491
           else if (vals->stable && tp->klass->base.is_beta)
492
             {
493
                _eo_parser_log(&tp->base, "beta class '%s' used in stable context",
494
                               tp->klass->base.name);
495
                return EINA_FALSE;
496
             }
497
           tp->ownable = EINA_TRUE;
498
           tp->base.c_name = eina_stringshare_ref(tp->klass->base.c_name);
499
           return _validate(&tp->base);
500
        }
501
      case EOLIAN_TYPE_ERROR:
502
        {
503
           tp->error = (Eolian_Error *)eolian_unit_error_by_name_get(src, tp->base.name);
504
           if (!tp->error)
505
             {
506
                _eo_parser_log(&tp->base, "undefined error %s "
507
                         "(likely wrong namespacing)", tp->base.name);
508
                return EINA_FALSE;
509
             }
510
           else if (vals->stable && tp->error->base.is_beta)
511
             {
512
                _eo_parser_log(&tp->base, "beta error '%s' used in stable context",
513
                               tp->error->base.name);
514
                return EINA_FALSE;
515
             }
516
           tp->base.c_name = eina_stringshare_ref(tp->error->base.c_name);
517
           if (tp->next_type && !_validate_type(vals, tp->next_type, EINA_FALSE, EINA_FALSE))
518
             return EINA_FALSE;
519
           return _validate(&tp->base);
520
        }
521
      default:
522
        break;
523
     }
524
   return EINA_FALSE;
525
}
526

527
static Eina_Bool
528
_validate_expr(Eolian_Expression *expr, const Eolian_Type *tp,
529
               Eolian_Expression_Mask msk, Eina_Bool by_ref)
530
{
531
   Eolian_Value val;
532
   if (by_ref)
533
     val = database_expr_eval(expr->base.unit, expr, EOLIAN_MASK_NULL, NULL, NULL);
534
   else if (tp)
535
     val = database_expr_eval_type(expr->base.unit, expr, tp, NULL, NULL);
536
   else
537
     val = database_expr_eval(expr->base.unit, expr, msk, NULL, NULL);
538

539
   if (val.type == EOLIAN_EXPR_UNKNOWN)
540
     return EINA_FALSE;
541

542
   return _validate(&expr->base);
543
}
544

545
static Eina_Bool
546
_validate_param(Validate_State *vals, Eolian_Function_Parameter *param)
547
{
548
   if (!_validate_type_by_ref(vals, param->type, param->by_ref, param->move, EINA_FALSE))
549
     return EINA_FALSE;
550

551
   if (param->value && !_validate_expr(param->value, param->type, 0, param->by_ref))
552
     return EINA_FALSE;
553

554
   if (!_validate_doc(param->doc))
555
     return EINA_FALSE;
556

557
   return _validate(&param->base);
558
}
559

560
static Eina_Bool
561
_validate_function(Validate_State *vals, Eolian_Function *func, Eina_Hash *nhash)
562
{
563
   Eina_List *l;
564
   Eolian_Function_Parameter *param;
565

566
   const Eolian_Object *oobj = nhash ? eina_hash_find(nhash, &func->base.name) : NULL;
567
   if (EINA_UNLIKELY(oobj && (oobj != &func->base)))
568
     {
569
        _eo_parser_log(&func->base,
570
                 "%sfunction '%s' conflicts with another symbol (at %s:%d:%d)",
571
                 func->base.is_beta ? "beta " : "", func->base.name, oobj->file,
572
                 oobj->line, oobj->column);
573
        vals->warned = EINA_TRUE;
574
     }
575

576
   /* if already validated, no need to perform the other checks...
577
    * but duplicate checks need to be performed every time
578
    */
579
   if (func->base.validated)
580
     {
581
        /* it might be validated, but need to add it anyway */
582
        if (!oobj && nhash)
583
          eina_hash_add(nhash, &func->base.name, &func->base);
584
        return EINA_TRUE;
585
     }
586

587
   /* need to preserve stable flag set from the class */
588
   Eina_Bool was_stable = _set_stable(vals, !func->base.is_beta && vals->stable);
589

590
   if (func->get_ret_type && !_validate_type_by_ref(vals, func->get_ret_type,
591
       func->get_return_by_ref, func->get_return_move, EINA_TRUE))
592
     return _reset_stable(vals, was_stable, EINA_FALSE);
593

594
   if (func->set_ret_type && !_validate_type_by_ref(vals, func->set_ret_type,
595
       func->set_return_by_ref, func->set_return_move, EINA_TRUE))
596
     return _reset_stable(vals, was_stable, EINA_FALSE);
597

598
   if (func->get_ret_val && !_validate_expr(func->get_ret_val,
599
                                            func->get_ret_type, 0,
600
                                            func->get_return_by_ref))
601
     return _reset_stable(vals, was_stable, EINA_FALSE);
602

603
   if (func->set_ret_val && !_validate_expr(func->set_ret_val,
604
                                            func->set_ret_type, 0,
605
                                            func->set_return_by_ref))
606
     return _reset_stable(vals, was_stable, EINA_FALSE);
607

608
#define EOLIAN_PARAMS_VALIDATE(params) \
609
   EINA_LIST_FOREACH(params, l, param) \
610
     if (!_validate_param(vals, param)) \
611
       return _reset_stable(vals, was_stable, EINA_FALSE);
612

613
   EOLIAN_PARAMS_VALIDATE(func->prop_values);
614
   EOLIAN_PARAMS_VALIDATE(func->prop_values_get);
615
   EOLIAN_PARAMS_VALIDATE(func->prop_values_set);
616
   EOLIAN_PARAMS_VALIDATE(func->prop_keys);
617
   EOLIAN_PARAMS_VALIDATE(func->prop_keys_get);
618
   EOLIAN_PARAMS_VALIDATE(func->prop_keys_set);
619

620
#undef EOLIAN_PARAMS_VALIDATE
621

622
   if (!_validate_doc(func->get_return_doc))
623
     return _reset_stable(vals, was_stable, EINA_FALSE);
624
   if (!_validate_doc(func->set_return_doc))
625
     return _reset_stable(vals, was_stable, EINA_FALSE);
626

627
   /* just for now, when dups become errors there will be no need to check */
628
   if (!oobj && nhash)
629
     eina_hash_add(nhash, &func->base.name, &func->base);
630

631
   _reset_stable(vals, was_stable, EINA_TRUE);
632
   return _validate(&func->base);
633
}
634

635
static Eina_Bool
636
_validate_part(Validate_State *vals, Eolian_Part *part, Eina_Hash *phash)
637
{
638
   const Eolian_Object *oobj = eina_hash_find(phash, &part->base.name);
639
   if (oobj)
640
     {
641
        _eo_parser_log(&part->base,
642
                 "part '%s' conflicts with another part (at %s:%d:%d)",
643
                 part->base.name, oobj->file, oobj->line, oobj->column);
644
        vals->warned = EINA_TRUE;
645
     }
646

647
   /* see _validate_function above */
648
   if (part->base.validated)
649
     {
650
        if (!oobj)
651
          eina_hash_add(phash, &part->base.name, &part->base);
652
        return EINA_TRUE;
653
     }
654

655
   Eina_Bool was_stable = _set_stable(vals, !part->base.is_beta && vals->stable);
656

657
   if (!_validate_doc(part->doc))
658
     return _reset_stable(vals, was_stable, EINA_FALSE);
659
   if (!_validate_doc_since_reset(vals, part->doc))
660
     return _reset_stable(vals, was_stable, EINA_FALSE);
661

662
   /* switch the class name for class */
663
   Eolian_Class *pcl = eina_hash_find(part->base.unit->classes, part->klass_name);
664
   if (!pcl)
665
     {
666
        _eo_parser_log(&part->base, "unknown part class '%s' (incorrect case?)",
667
                 part->klass_name);
668
        return _reset_stable(vals, was_stable, EINA_FALSE);
669
     }
670
   else if (vals->stable && pcl->base.is_beta)
671
     {
672
        _eo_parser_log(&part->base, "beta part class '%s' used in stable context",
673
                       pcl->base.name);
674
        return _reset_stable(vals, was_stable, EINA_FALSE);
675
     }
676
   eina_stringshare_del(part->klass_name);
677
   part->klass = pcl;
678

679
   if (!oobj)
680
     eina_hash_add(phash, &part->base.name, &part->base);
681

682
   _reset_stable(vals, was_stable, EINA_TRUE);
683
   return _validate(&part->base);
684
}
685

686
static Eina_Bool
687
_validate_event(Validate_State *vals, Eolian_Event *event, Eina_Hash *nhash)
688
{
689
   const Eolian_Object *oobj = NULL;
690

691
   oobj = eina_hash_find(nhash, &event->base.name);
692
   if (EINA_UNLIKELY(!!oobj))
693
     {
694
        _eo_parser_log(&event->base,
695
                 "event '%s' conflicts with another event (at %s:%d:%d)",
696
                 event->base.name, oobj->file, oobj->line, oobj->column);
697
        vals->warned = EINA_TRUE;
698
     }
699

700
   if (event->base.validated)
701
     {
702
        eina_hash_set(nhash, &event->base.name, &event->base);
703
        return EINA_TRUE;
704
     }
705

706
   Eina_Bool was_stable = _set_stable(vals, !event->base.is_beta && vals->stable);
707

708
   if (!_validate_type(vals, event->type, EINA_FALSE, EINA_FALSE))
709
     return _reset_stable(vals, was_stable, EINA_FALSE);
710

711
   /* if this is an alias we need the lowest type in the stack, this is
712
    * after validation so all the necessary fields are properly filled in
713
    */
714
   const Eolian_Type *tp = eolian_type_aliased_base_get(event->type);
715

716
   /* event types are specially restricted
717
    * but stuff like pointer-to-pointer is alrady handled by _validate_type
718
    */
719
   if (tp->type == EOLIAN_TYPE_REGULAR && vals->stable)
720
     {
721
        /* explicit pointers never allowed */
722
        if (tp->is_ptr)
723
          {
724
             _eo_parser_log(&tp->base, "pointers not allowed in events");
725
             return _reset_stable(vals, was_stable, EINA_FALSE);
726
          }
727
        int kwid = eo_lexer_keyword_str_to_id(tp->base.name);
728
        /* require containers to be const for now...
729
         *
730
         * this is FIXME, and decision wasn't reached before 1.22
731
         * it is a simple search-replace anyway
732
         */
733
        if (database_type_is_ownable(tp->base.unit, tp, EINA_FALSE, NULL))
734
          {
735
             switch (kwid)
736
               {
737
                case KW_string:
738
                case KW_stringshare:
739
                  break;
740
                default:
741
                  if (!tp->is_const)
742
                    {
743
                       _eo_parser_log(&tp->base, "event container types must be const");
744
                       return _reset_stable(vals, was_stable, EINA_FALSE);
745
                    }
746
               }
747
          }
748
        else if (tp->is_const)
749
          {
750
             _eo_parser_log(&tp->base, "event value types cannot be const");
751
             return _reset_stable(vals, was_stable, EINA_FALSE);
752
          }
753
        /* containers are allowed but not iterators/lists */
754
        if (kwid == KW_iterator || kwid == KW_list)
755
          {
756
             _eo_parser_log(&tp->base, "sequence containers not allowed in events");
757
             return _reset_stable(vals, was_stable, EINA_FALSE);
758
          }
759
        /* rw slices are not allowed as regular types are always immutable */
760
        if (kwid == KW_rw_slice)
761
          {
762
             _eo_parser_log(&tp->base, "mutable slices not allowed in events");
763
             return _reset_stable(vals, was_stable, EINA_FALSE);
764
          }
765
        /* any type past builtin value types and containers is not allowed,
766
         * any_value is allowed but passed as const reference, any_value_ref
767
         * is not; string and stringshare is allowed, but mutable strings are
768
         * not and neither are string buffers, the type is never owned by the
769
         * callee, so all strings passed in are unowned and read-only
770
         */
771
        if (kwid >= KW_any_value_ref && kwid != KW_string && kwid != KW_stringshare)
772
          {
773
             _eo_parser_log(&tp->base, "forbidden event type");
774
             return _reset_stable(vals, was_stable, EINA_FALSE);
775
          }
776
     }
777

778
   if (!_validate_doc(event->doc))
779
     return _reset_stable(vals, was_stable, EINA_FALSE);
780
   if (!_validate_doc_since_reset(vals, event->doc))
781
     return _reset_stable(vals, was_stable, EINA_FALSE);
782

783
   eina_hash_set(nhash, &event->base.name, &event->base);
784

785
   _reset_stable(vals, was_stable, EINA_TRUE);
786
   return _validate(&event->base);
787
}
788

789
const Eolian_Class *
790
_get_impl_class(const Eolian_Class *cl, const char *cln)
791
{
792
   if (!cl || !strcmp(cl->base.name, cln))
793
     return cl;
794
   Eina_List *l;
795
   Eolian_Class *icl = cl->parent;
796
   if (icl)
797
     {
798
        /* we can do a depth first search, it's easier and doesn't matter
799
         * which part of the inheritance tree we find the class in
800
         */
801
        const Eolian_Class *fcl = _get_impl_class(icl, cln);
802
        if (fcl)
803
          return fcl;
804
     }
805
   EINA_LIST_FOREACH(cl->requires, l, icl)
806
     {
807
        const Eolian_Class *fcl = _get_impl_class(icl, cln);
808
        if (fcl)
809
          return fcl;
810
     }
811
   EINA_LIST_FOREACH(cl->extends, l, icl)
812
     {
813
        const Eolian_Class *fcl = _get_impl_class(icl, cln);
814
        if (fcl)
815
          return fcl;
816
     }
817
   return NULL;
818
}
819

820
static Eina_Bool
821
_db_fill_implement(Eolian_Class *cl, Eolian_Implement *impl)
822
{
823
   Eolian_Function_Type ftype = EOLIAN_METHOD;
824

825
   if (impl->is_prop_get && impl->is_prop_set)
826
     ftype = EOLIAN_PROPERTY;
827
   else if (impl->is_prop_get)
828
     ftype = EOLIAN_PROP_GET;
829
   else if (impl->is_prop_set)
830
     ftype = EOLIAN_PROP_SET;
831

832
   size_t imlen = strlen(impl->base.name);
833
   char *clbuf = alloca(imlen + 1);
834
   memcpy(clbuf, impl->base.name, imlen + 1);
835

836
   char *ldot = strrchr(clbuf, '.');
837
   if (!ldot)
838
     return EINA_FALSE; /* unreachable in practice, for static analysis */
839

840
   *ldot = '\0'; /* split between class name and func name */
841
   const char *clname = clbuf;
842
   const char *fnname = ldot + 1;
843

844
   const Eolian_Class *tcl = _get_impl_class(cl, clname);
845
   if (!tcl)
846
     {
847
        _eo_parser_log(&impl->base, "class '%s' not found within the inheritance tree of '%s'",
848
                       clname, cl->base.name);
849
        return EINA_FALSE;
850
     }
851

852
   impl->klass = tcl;
853
   impl->implklass = cl;
854

855
   const Eolian_Function *fid = eolian_class_function_by_name_get(tcl, fnname, EOLIAN_UNRESOLVED);
856
   if (!fid)
857
     {
858
        _eo_parser_log(&impl->base, "function '%s' not known in class '%s'", fnname, clname);
859
        return EINA_FALSE;
860
     }
861

862
   Eolian_Function_Type aftype = eolian_function_type_get(fid);
863

864
   Eina_Bool auto_empty = (impl->get_auto || impl->get_empty);
865

866
   /* match implement type against function type */
867
   if (ftype == EOLIAN_PROPERTY)
868
     {
869
        /* property */
870
        if (aftype != EOLIAN_PROPERTY)
871
          {
872
             _eo_parser_log(&impl->base, "function '%s' is not a complete property", fnname);
873
             return EINA_FALSE;
874
          }
875
        auto_empty = auto_empty && (impl->set_auto || impl->set_empty);
876
     }
877
   else if (ftype == EOLIAN_PROP_SET)
878
     {
879
        /* setter */
880
        if ((aftype != EOLIAN_PROP_SET) && (aftype != EOLIAN_PROPERTY))
881
          {
882
             _eo_parser_log(&impl->base, "function '%s' doesn't have a setter", fnname);
883
             return EINA_FALSE;
884
          }
885
        auto_empty = (impl->set_auto || impl->set_empty);
886
     }
887
   else if (ftype == EOLIAN_PROP_GET)
888
     {
889
        /* getter */
890
        if ((aftype != EOLIAN_PROP_GET) && (aftype != EOLIAN_PROPERTY))
891
          {
892
             _eo_parser_log(&impl->base, "function '%s' doesn't have a getter", fnname);
893
             return EINA_FALSE;
894
          }
895
     }
896
   else if (aftype != EOLIAN_METHOD)
897
     {
898
        _eo_parser_log(&impl->base, "function '%s' is not a method", fnname);
899
        return EINA_FALSE;
900
     }
901

902
   if ((fid->klass == cl) && !auto_empty)
903
     {
904
        /* only allow explicit implements from other classes, besides auto and
905
         * empty... also prevents pure virtuals from being implemented
906
         */
907
        _eo_parser_log(&impl->base, "invalid implement '%s'", impl->base.name);
908
        return EINA_FALSE;
909
     }
910

911
   impl->foo_id = fid;
912

913
   return EINA_TRUE;
914
}
915

916
typedef enum
917
{
918
   IMPL_STATUS_NONE = 1,
919
   IMPL_STATUS_FULL,
920
   IMPL_STATUS_GET,
921
   IMPL_STATUS_SET
922
} Impl_Status;
923

924
static Eina_Bool
925
_extend_impl(Eina_Hash *fs, Eolian_Implement *impl, Eina_Bool as_iface)
926
{
927
   const Eolian_Function *fid = impl->foo_id;
928
   Impl_Status st = (Impl_Status)eina_hash_find(fs, &fid);
929
   if (st == IMPL_STATUS_FULL)
930
     return EINA_FALSE;
931
   if (!st)
932
     eina_hash_set(fs, &fid, (void *)IMPL_STATUS_NONE);
933
   if (as_iface || (impl->implklass->type == EOLIAN_CLASS_INTERFACE))
934
     return !st;
935
   /* impl covers entire declaration */
936
   if (fid->type == EOLIAN_METHOD ||
937
       ((st == IMPL_STATUS_GET || fid->type == EOLIAN_PROP_SET) && impl->is_prop_set) ||
938
       ((st == IMPL_STATUS_SET || fid->type == EOLIAN_PROP_GET) && impl->is_prop_get) ||
939
       (impl->is_prop_get && impl->is_prop_set))
940
     {
941
        /* different implementing class can only do a real implementation */
942
        if (impl->implklass != impl->klass)
943
          {
944
             eina_hash_set(fs, &fid, (void *)IMPL_STATUS_FULL);
945
             return (st != IMPL_STATUS_FULL);
946
          }
947
        /* entirely virtual, so bail out always */
948
        if (impl->get_pure_virtual && impl->set_pure_virtual)
949
          return !st;
950
        if (impl->get_pure_virtual)
951
          {
952
             if (fid->type == EOLIAN_METHOD || fid->type == EOLIAN_PROP_GET)
953
               return !st;
954
             if (st == IMPL_STATUS_GET)
955
               {
956
                  eina_hash_set(fs, &fid, (void *)IMPL_STATUS_FULL);
957
                  return (st != IMPL_STATUS_FULL);
958
               }
959
             else
960
               {
961
                  eina_hash_set(fs, &fid, (void *)IMPL_STATUS_SET);
962
                  return (st <= IMPL_STATUS_NONE);
963
               }
964
          }
965
        if (impl->set_pure_virtual)
966
          {
967
             if (fid->type == EOLIAN_PROP_SET)
968
               return !st;
969
             if (st == IMPL_STATUS_SET)
970
               {
971
                  eina_hash_set(fs, &fid, (void *)IMPL_STATUS_FULL);
972
                  return (st < IMPL_STATUS_FULL);
973
               }
974
             else
975
               {
976
                  eina_hash_set(fs, &fid, (void *)IMPL_STATUS_GET);
977
                  return (st <= IMPL_STATUS_NONE);
978
               }
979
          }
980
        eina_hash_set(fs, &fid, (void *)IMPL_STATUS_FULL);
981
        return (st != IMPL_STATUS_FULL);
982
     }
983
   if (impl->implklass != impl->klass ||
984
       (!impl->get_pure_virtual && !impl->set_pure_virtual))
985
     {
986
        if (impl->is_prop_get)
987
          {
988
             eina_hash_set(fs, &fid, (void *)IMPL_STATUS_GET);
989
             return (st <= IMPL_STATUS_NONE);
990
          }
991
        else if (impl->is_prop_set)
992
          {
993
             eina_hash_set(fs, &fid, (void *)IMPL_STATUS_SET);
994
             return (st <= IMPL_STATUS_NONE);
995
          }
996
     }
997
   return !st;
998
}
999

1000
/* fills a complete set of stuff implemented or inherited on a class
1001
 * this is used to check whether to auto-add composited interfaces into
1002
 * implemented/extended list
1003
 */
1004
static void
1005
_db_fill_ihash(Eolian_Class *icl, Eina_Hash *icls)
1006
{
1007
   if (icl->parent)
1008
     _db_fill_ihash(icl->parent, icls);
1009
   Eina_List *l;
1010
   Eolian_Class *sicl;
1011
   EINA_LIST_FOREACH(icl->extends, l, sicl)
1012
     _db_fill_ihash(sicl, icls);
1013
   eina_hash_set(icls, &icl, icl);
1014
}
1015

1016
static void
1017
_db_fill_callables(Eolian_Class *cl, Eolian_Class *icl, Eina_Hash *fs, Eina_Bool parent)
1018
{
1019
   Eina_List *l;
1020
   Eolian_Implement *impl;
1021
   Eina_Bool allow_impl = parent || (icl->type == EOLIAN_CLASS_MIXIN);
1022
   EINA_LIST_FOREACH(icl->callables, l, impl)
1023
     {
1024
        Impl_Status ost = (Impl_Status)eina_hash_find(fs, &impl->foo_id);
1025
        /* while regular classes are already fully checked and one may
1026
         * assume that we could just make everything coming from regular
1027
         * classes IMPL_STATUS_FULL, we still need to account for all of
1028
         * the callables of the regular class, as the full implementation
1029
         * may come from somewhere deeper in the inheritance tree and we
1030
         * may not reach it first, so follow the same logic for all
1031
         */
1032
        if (_extend_impl(fs, impl, !allow_impl))
1033
          {
1034
             /* we had an unimplementation in the list, replace
1035
              * instead of appending the new thing to callables
1036
              * this is a corner case, it shouldn't happen much
1037
              */
1038
             if (ost == IMPL_STATUS_NONE)
1039
               {
1040
                  Eina_List *ll;
1041
                  Eolian_Implement *old;
1042
                  EINA_LIST_FOREACH(cl->callables, ll, old)
1043
                    {
1044
                       if (old->foo_id == impl->foo_id)
1045
                         eina_list_data_set(ll, impl);
1046
                    }
1047
               }
1048
             else
1049
               cl->callables = eina_list_append(cl->callables, impl);
1050
          }
1051
     }
1052
}
1053

1054
static Eina_Bool
1055
_db_check_implemented(Validate_State *vals, Eolian_Class *cl, Eina_Hash *fs,
1056
                      Eina_Hash *cs, Eina_Hash *errh)
1057
{
1058
   if (cl->type != EOLIAN_CLASS_REGULAR)
1059
     return EINA_TRUE;
1060

1061
   Eina_Bool succ = EINA_TRUE;
1062

1063
   /* class is beta and we didn't enable unimplemented checking for those */
1064
   if (!vals->unimplemented_beta && cl->base.is_beta)
1065
     return EINA_TRUE;
1066

1067
   Eina_List *l;
1068
   Eolian_Implement *impl;
1069
   EINA_LIST_FOREACH(cl->callables, l, impl)
1070
     {
1071
        const Eolian_Function *fid = impl->foo_id;
1072
        /* not checking beta and the function is beta: skip */
1073
        if (!vals->unimplemented_beta && fid->base.is_beta)
1074
          continue;
1075
        /* not checking beta and the function's class is beta: skip */
1076
        if (!vals->unimplemented_beta && fid->klass->base.is_beta)
1077
          continue;
1078
        Impl_Status st = (Impl_Status)eina_hash_find(fs, &fid);
1079
        /* found an interface this func was originally defined in in the
1080
         * composite list; in that case, ignore it and assume it will come
1081
         * from a composite object later
1082
         */
1083
        if (eina_hash_find(cs, &fid->klass))
1084
          continue;
1085
        /* the error on this impl has already happened, which means it came
1086
         * from another regular class; reduce verbosity by not repeating it
1087
         */
1088
        if (eina_hash_find(errh, &impl))
1089
          continue;
1090
        switch (st)
1091
          {
1092
           case IMPL_STATUS_NONE:
1093
             _eo_parser_log(
1094
               &cl->base, "unimplemented function '%s' (originally defined at %s:%d:%d)",
1095
               fid->base.name, fid->base.file, fid->base.line, fid->base.column);
1096
             succ = EINA_FALSE;
1097
             eina_hash_set(errh, &impl, impl);
1098
             continue;
1099
           case IMPL_STATUS_GET:
1100
           case IMPL_STATUS_SET:
1101
             _eo_parser_log(
1102
               &cl->base, "partially implemented function '%s' (originally defined at %s:%d:%d)",
1103
               fid->base.name, fid->base.file, fid->base.line, fid->base.column);
1104
             succ = EINA_FALSE;
1105
             eina_hash_set(errh, &impl, impl);
1106
             continue;
1107
           case IMPL_STATUS_FULL:
1108
             continue;
1109
           default:
1110
             _eo_parser_log(
1111
               &cl->base, "internal error, unregistered function '%s' (originally defined at %s:%d:%d)",
1112
               fid->base.name, fid->base.file, fid->base.line, fid->base.column);
1113
             return EINA_FALSE;
1114
          }
1115
     }
1116
   return succ;
1117
}
1118

1119
static Eina_Bool
1120
_db_fill_implements(Eolian_Class *cl, Eina_Hash *fs)
1121
{
1122
   Eolian_Implement *impl;
1123
   Eina_List *l;
1124

1125
   Eina_Bool ret = EINA_TRUE;
1126

1127
   Eina_Hash *th = eina_hash_string_small_new(NULL),
1128
             *pth = eina_hash_string_small_new(NULL);
1129
   EINA_LIST_FOREACH(cl->implements, l, impl)
1130
     {
1131
        Eina_Bool prop = (impl->is_prop_get || impl->is_prop_set);
1132
        if (eina_hash_find(prop ? pth : th, impl->base.name))
1133
          {
1134
             _eo_parser_log(&impl->base, "duplicate implement '%s'", impl->base.name);
1135
             ret = EINA_FALSE;
1136
             goto end;
1137
          }
1138
        if (impl->klass != cl)
1139
          {
1140
             if (!_db_fill_implement(cl, impl))
1141
               {
1142
                  ret = EINA_FALSE;
1143
                  goto end;
1144
               }
1145
             if (eolian_function_is_constructor(impl->foo_id, impl->klass))
1146
               database_function_constructor_add((Eolian_Function *)impl->foo_id, cl);
1147
          }
1148
        if ((impl->klass != cl) && !_db_fill_implement(cl, impl))
1149
          {
1150
             ret = EINA_FALSE;
1151
             goto end;
1152
          }
1153
        cl->callables = eina_list_append(cl->callables, impl);
1154
        eina_hash_add(prop ? pth : th, impl->base.name, impl->base.name);
1155
        _extend_impl(fs, impl, cl->type == EOLIAN_CLASS_INTERFACE);
1156
     }
1157

1158
end:
1159
   eina_hash_free(th);
1160
   eina_hash_free(pth);
1161
   return ret;
1162
}
1163

1164
static Eina_Bool
1165
_db_fill_ctors(Eolian_Class *cl)
1166
{
1167
   Eolian_Constructor *ctor;
1168
   Eina_List *l;
1169

1170
   Eina_Bool ret = EINA_TRUE;
1171

1172
   Eina_Hash *th = eina_hash_string_small_new(NULL);
1173
   EINA_LIST_FOREACH(cl->constructors, l, ctor)
1174
     {
1175
        if (eina_hash_find(th, ctor->base.name))
1176
          {
1177
             _eo_parser_log(&ctor->base, "duplicate ctor '%s'", ctor->base.name);
1178
             ret = EINA_FALSE;
1179
             goto end;
1180
          }
1181
        const char *ldot = strrchr(ctor->base.name, '.');
1182
        if (!ldot)
1183
          {
1184
             ret = EINA_FALSE;
1185
             goto end;
1186
          }
1187
        char *cnbuf = alloca(ldot - ctor->base.name + 1);
1188
        memcpy(cnbuf, ctor->base.name, ldot - ctor->base.name);
1189
        cnbuf[ldot - ctor->base.name] = '\0';
1190
        const Eolian_Class *tcl = _get_impl_class(cl, cnbuf);
1191
        if (!tcl)
1192
          {
1193
             _eo_parser_log(&ctor->base, "class '%s' not found within the inheritance tree of '%s'",
1194
                            cnbuf, cl->base.name);
1195
             ret = EINA_FALSE;
1196
             goto end;
1197
          }
1198
        ctor->klass = tcl;
1199
        const Eolian_Function *cfunc = eolian_constructor_function_get(ctor);
1200
        if (!cfunc)
1201
          {
1202
             _eo_parser_log(&ctor->base, "unable to find function '%s'", ctor->base.name);
1203
             ret = EINA_FALSE;
1204
             goto end;
1205
          }
1206
        database_function_constructor_add((Eolian_Function *)cfunc, tcl);
1207
        eina_hash_add(th, ctor->base.name, ctor->base.name);
1208
     }
1209

1210
end:
1211
   eina_hash_free(th);
1212
   return ret;
1213
}
1214

1215
static Eina_Bool
1216
_db_swap_inherit(Eolian_Class *cl, Eina_Bool succ, Eina_Stringshare *in_cl,
1217
                 Eolian_Class **out_cl, Eina_Bool iface_only)
1218
{
1219
   if (!succ)
1220
     {
1221
        eina_stringshare_del(in_cl);
1222
        return EINA_FALSE;
1223
     }
1224
   Eolian_Class *icl = eina_hash_find(cl->base.unit->classes, in_cl);
1225
   if (!icl)
1226
     {
1227
        succ = EINA_FALSE;
1228
        _eo_parser_log(&cl->base, "unknown inherit '%s' (incorrect case?)", in_cl);
1229
     }
1230
   else if (iface_only && (icl->type != EOLIAN_CLASS_INTERFACE))
1231
     {
1232
        succ = EINA_FALSE;
1233
        _eo_parser_log(&cl->base, "non-interface class '%s' in composite list", icl->base.name);
1234
     }
1235
   else
1236
     *out_cl = icl;
1237
   eina_stringshare_del(in_cl);
1238
   return succ;
1239
}
1240

1241
/* this is so we can inherit composite lists into regular classes
1242
 * it doesn't need to be recursive since the parent/extension already
1243
 * has its composite stuff filled in from before
1244
 */
1245
static void
1246
_add_composite(Eolian_Class *cl, const Eolian_Class *icl, Eina_Hash *ch)
1247
{
1248
   const Eolian_Class *ccl;
1249
   Eina_List *l;
1250
   EINA_LIST_FOREACH(icl->composite, l, ccl)
1251
     {
1252
        if (eina_hash_find(ch, &ccl))
1253
          continue;
1254
        cl->composite = eina_list_append(cl->composite, ccl);
1255
        eina_hash_add(ch, &ccl, ccl);
1256
     }
1257
}
1258

1259
static void
1260
_add_implicit_composite(Eolian_Class *icl, Eina_Hash *ch, Eina_Bool try_tree)
1261
{
1262
   eina_hash_set(ch, &icl, icl);
1263
   if (!try_tree)
1264
     return;
1265
   Eina_List *l;
1266
   EINA_LIST_FOREACH(icl->extends, l, icl)
1267
     _add_implicit_composite(icl, ch, try_tree);
1268
}
1269

1270
static Eina_Bool
1271
_db_fill_inherits(Validate_State *vals, Eolian_Class *cl, Eina_Hash *fhash,
1272
                  Eina_Hash *errh)
1273
{
1274
   if (eina_hash_find(fhash, &cl->base.name))
1275
     return EINA_TRUE;
1276

1277
   /* already merged outside of staging, therefore validated, and skipped */
1278
   if (eina_hash_find(cl->base.unit->state->main.unit.classes, cl->base.name))
1279
     return EINA_TRUE;
1280

1281
   Eina_List *il = cl->extends, *rl = cl->requires;
1282
   Eina_Stringshare *inn = NULL;
1283
   cl->extends = NULL;
1284
   cl->requires = NULL;
1285
   Eina_Bool succ = EINA_TRUE;
1286

1287
   if (cl->parent_name)
1288
     {
1289
        succ = _db_swap_inherit(cl, succ, cl->parent_name, &cl->parent, EINA_FALSE);
1290
        if (succ)
1291
          {
1292
             /* fill if not found, but do not return right away because
1293
              * the rest of the list needs to be freed in order not to
1294
              * leak any memory
1295
              */
1296
             succ = _db_fill_inherits(vals, cl->parent, fhash, errh);
1297
          }
1298
     }
1299

1300
   EINA_LIST_FREE(il, inn)
1301
     {
1302
        Eolian_Class *out_cl = NULL;
1303
        succ = _db_swap_inherit(cl, succ, inn, &out_cl, EINA_FALSE);
1304
        if (!succ)
1305
          continue;
1306
        cl->extends = eina_list_append(cl->extends, out_cl);
1307
        succ = _db_fill_inherits(vals, out_cl, fhash, errh);
1308
     }
1309

1310
   if (succ && cl->type == EOLIAN_CLASS_MIXIN)
1311
     {
1312
        EINA_LIST_FREE(rl, inn)
1313
          {
1314
             Eolian_Class *out_cl = NULL;
1315
             succ = _db_swap_inherit(cl, succ, inn, &out_cl, EINA_FALSE);
1316
             if (succ && !(out_cl->type == EOLIAN_CLASS_REGULAR || out_cl->type == EOLIAN_CLASS_ABSTRACT))
1317
               {
1318
                  _eo_parser_log(&cl->base, "requires only allows regulars or abstracts");
1319
                  succ = EINA_FALSE;
1320
               }
1321
             if (succ)
1322
               {
1323
                 _db_fill_inherits(vals, out_cl, fhash, errh);
1324
               }
1325
             if (!succ)
1326
               continue;
1327
             if (!eina_list_data_find(cl->requires, out_cl))
1328
               cl->requires = eina_list_append(cl->requires, out_cl);
1329
          }
1330
     }
1331

1332
   /* a set of interfaces for quick checks */
1333
   Eina_Hash *ch = eina_hash_pointer_new(NULL);
1334

1335
   /* replace the composite list with real instances and initial-fill the hash */
1336
   il = cl->composite;
1337
   cl->composite = NULL;
1338
   int ncomp = 0;
1339
   EINA_LIST_FREE(il, inn)
1340
     {
1341
        Eolian_Class *out_cl = NULL;
1342
        succ = _db_swap_inherit(cl, succ, inn, &out_cl, EINA_TRUE);
1343
        if (!succ)
1344
          continue;
1345
        cl->composite = eina_list_append(cl->composite, out_cl);
1346
        succ = _db_fill_inherits(vals, out_cl, fhash, errh);
1347
        ++ncomp;
1348
        /* for each thing that is composited, we need to add the entire
1349
         * inheritance tree of it into composite hash to check, so e.g.
1350
         * class A -> composites B -> extends C does not complain about
1351
         * A not implementing C
1352
         */
1353
        _add_implicit_composite(out_cl, ch, out_cl->type == EOLIAN_CLASS_INTERFACE);
1354
     }
1355

1356
   /* parent can be abstract, those are not checked for unimplemented,
1357
    * plus later we'll be exposing composite as an API, so we need to add
1358
    * all composite interfaces from everywhere in the inheritance tree anyway
1359
    */
1360
   if (cl->parent)
1361
     _add_composite(cl, cl->parent, ch);
1362

1363
   /* iterate extensions, add any composite stuff into the hash as well */
1364
   Eolian_Class *icl;
1365
   EINA_LIST_FOREACH(cl->extends, il, icl)
1366
     _add_composite(cl, icl, ch);
1367

1368
   /* failed on the way, no point in filling further
1369
    * the failed stuff will get dropped so it's ok if it's inconsistent
1370
    */
1371
   if (!succ)
1372
     {
1373
        eina_hash_free(ch);
1374
        return EINA_FALSE;
1375
     }
1376

1377
   eina_hash_add(fhash, &cl->base.name, cl);
1378

1379
   /* there are more than zero of composites of its own */
1380
   if (ncomp > 0)
1381
     {
1382
        /* this one stores what is already in inheritance tree */
1383
        Eina_Hash *ih = eina_hash_pointer_new(NULL);
1384

1385
        /* fill a complete inheritance tree set */
1386
        if (cl->parent)
1387
          _db_fill_ihash(cl->parent, ih);
1388

1389
        EINA_LIST_FOREACH(cl->extends, il, icl)
1390
          _db_fill_ihash(icl, ih);
1391

1392
        /* go through only the explicitly specified composite list part, as the
1393
         * rest was to be handled in parents already... add what hasn't been
1394
         * explicitly implemented so far into implements/extends
1395
         */
1396
        EINA_LIST_FOREACH(cl->composite, il, icl)
1397
          {
1398
             /* ran out of classes */
1399
             if (!ncomp--)
1400
               break;
1401
             /* found in inheritance tree, skip */
1402
             if (eina_hash_find(ih, &icl))
1403
               continue;
1404
             cl->extends = eina_list_append(cl->extends, icl);
1405
          }
1406

1407
        eina_hash_free(ih);
1408
     }
1409

1410
   /* stores mappings from function to Impl_Status */
1411
   Eina_Hash *fh = eina_hash_pointer_new(NULL);
1412

1413
   /* make sure impls/ctors are filled first, but do it only once */
1414
   if (!_db_fill_implements(cl, fh))
1415
     {
1416
        eina_hash_free(ch);
1417
        eina_hash_free(fh);
1418
        return EINA_FALSE;
1419
     }
1420

1421
   if (!_db_fill_ctors(cl))
1422
     {
1423
        eina_hash_free(ch);
1424
        eina_hash_free(fh);
1425
        return EINA_FALSE;
1426
     }
1427

1428
   /* fill callables list with stuff from inheritance tree, the current
1429
    * class stuff is already filled in _db_fill_implements, this is needed
1430
    * in order to make sure all methods are implemented
1431
    */
1432
   if (cl->parent)
1433
     _db_fill_callables(cl, cl->parent, fh, EINA_TRUE);
1434

1435
   EINA_LIST_FOREACH(cl->extends, il, icl)
1436
     _db_fill_callables(cl, icl, fh, EINA_FALSE);
1437

1438
   /* verify that all methods are implemented on the class */
1439
   if (!_db_check_implemented(vals, cl, fh, ch, errh))
1440
     vals->warned = EINA_TRUE;
1441

1442
   eina_hash_free(fh);
1443
   eina_hash_free(ch);
1444

1445
   return EINA_TRUE;
1446
}
1447

1448
static Eina_Bool
1449
_validate_implement(Validate_State *vals, Eolian_Implement *impl)
1450
{
1451
   if (impl->base.validated)
1452
     return EINA_TRUE;
1453

1454
   if (!_validate_doc(impl->common_doc))
1455
     return EINA_FALSE;
1456
   if (!_validate_doc(impl->get_doc))
1457
     return EINA_FALSE;
1458
   if (!_validate_doc(impl->set_doc))
1459
     return EINA_FALSE;
1460

1461
   /* common doc inherits @since into get/set doc */
1462
   const char *old_since = vals->since_ver;
1463
   if (impl->common_doc && !_validate_doc_since(vals, impl->common_doc))
1464
     return EINA_FALSE;
1465
   if (!_validate_doc_since_reset(vals, impl->get_doc))
1466
     return EINA_FALSE;
1467
   if (!_validate_doc_since_reset(vals, impl->set_doc))
1468
     return EINA_FALSE;
1469
   vals->since_ver = old_since;
1470

1471
   return _validate(&impl->base);
1472
}
1473

1474
static Eina_List*
1475
_required_classes(Eolian_Class *mixin)
1476
{
1477
   Eina_List *result = NULL, *n;
1478
   Eolian_Class *extension;
1479

1480

1481
   result = eina_list_clone(mixin->requires);
1482

1483
   if (mixin->parent)
1484
     result = eina_list_merge(result, _required_classes(mixin->parent));
1485

1486
   EINA_LIST_FOREACH(mixin->extends, n, extension)
1487
     result = eina_list_merge(result, _required_classes(extension));
1488

1489
   return result;
1490
}
1491

1492
static Eina_Bool
1493
_validate_class(Validate_State *vals, Eolian_Class *cl,
1494
                Eina_Hash *nhash, Eina_Hash *ehash, Eina_Hash *phash, Eina_Hash *chash)
1495
{
1496
   Eina_List *l;
1497
   Eolian_Function *func;
1498
   Eolian_Event *event;
1499
   Eolian_Part *part;
1500
   Eolian_Implement *impl;
1501
   Eolian_Class *icl;
1502
   Eina_List *required_classes = NULL;
1503

1504
   if (!cl)
1505
     return EINA_FALSE; /* if this happens something is very wrong though */
1506

1507
   /* we've gone through this part */
1508
   if (eina_hash_find(chash, &cl))
1509
     return EINA_TRUE;
1510

1511
   Eina_Bool valid = cl->base.validated;
1512

1513
   if (cl->parent)
1514
     {
1515
        /* first inherit needs some checking done on it */
1516
        if (!valid) switch (cl->type)
1517
          {
1518
           case EOLIAN_CLASS_REGULAR:
1519
           case EOLIAN_CLASS_ABSTRACT:
1520
             if (cl->parent->type != EOLIAN_CLASS_REGULAR && cl->parent->type != EOLIAN_CLASS_ABSTRACT)
1521
               {
1522
                  _eo_parser_log(&cl->base, "regular classes ('%s') cannot inherit from non-regular classes ('%s')",
1523
                                 cl->base.name, cl->parent->base.name);
1524
                  return EINA_FALSE;
1525
               }
1526
             break;
1527
           default:
1528
             break;
1529
          }
1530
        if (!cl->base.is_beta && cl->parent->base.is_beta)
1531
          {
1532
             _eo_parser_log(&cl->base, "non-beta class cannot have beta parent");
1533
             return EINA_FALSE;
1534
          }
1535
        if (!_validate_class(vals, cl->parent, nhash, ehash, phash, chash))
1536
          return EINA_FALSE;
1537
     }
1538

1539
   EINA_LIST_FOREACH(cl->extends, l, icl)
1540
     {
1541
        if (icl->type == EOLIAN_CLASS_MIXIN)
1542
          {
1543
             Eina_List *res = _required_classes(icl);
1544
             Eolian_Class *required_class;
1545
             Eina_List *n;
1546
             EINA_LIST_FOREACH(res, n, required_class)
1547
               {
1548
                 if (!eina_list_data_find(required_classes, required_class))
1549
                   required_classes = eina_list_append(required_classes, required_class);
1550
               }
1551
          }
1552
        if (!valid) switch (icl->type)
1553
          {
1554
           case EOLIAN_CLASS_REGULAR:
1555
           case EOLIAN_CLASS_ABSTRACT:
1556
             /* regular class in extensions list, forbidden */
1557
             {
1558
                _eo_parser_log(&cl->base, "regular classes ('%s') cannot appear in extensions list of '%s'",
1559
                               icl->base.name, cl->base.name);
1560
                vals->warned = EINA_TRUE;
1561
                break;
1562
             }
1563
           default:
1564
             /* it's ok, interfaces are allowed */
1565
             break;
1566
          }
1567
        if (!_validate_class(vals, icl, nhash, ehash, phash, chash))
1568
          return EINA_FALSE;
1569
     }
1570
   if (cl->type == EOLIAN_CLASS_ABSTRACT || cl->type == EOLIAN_CLASS_REGULAR)
1571
     {
1572
        //walk up the parent list and remove all classes from there
1573
        icl = cl;
1574
        while (icl)
1575
          {
1576
             required_classes = eina_list_remove(required_classes, icl);
1577
             icl = icl->parent;
1578
          }
1579
        //if there are a few left, drop, and error
1580
        if (required_classes)
1581
          {
1582
             Eina_Strbuf *classes = eina_strbuf_new();
1583
             Eolian_Class *required_class;
1584
             Eina_List *n;
1585
             EINA_LIST_FOREACH(required_classes, n, required_class)
1586
               {
1587
                   eina_strbuf_append(classes, required_class->base.name);
1588
                   eina_strbuf_append_char(classes, ' ');
1589
               }
1590
             _eo_parser_log(&cl->base, "required classes %sare not in the inherit chain of %s",
1591
                            eina_strbuf_string_get(classes), cl->base.name);
1592
             eina_strbuf_free(classes);
1593
             return EINA_FALSE;
1594
          }
1595
     }
1596

1597
   _set_stable(vals, !cl->base.is_beta);
1598
   vals->since_ver = NULL;
1599

1600
   if (!_validate_doc_since(vals, cl->doc))
1601
     return EINA_FALSE;
1602

1603
   EINA_LIST_FOREACH(cl->properties, l, func)
1604
     if (!_validate_function(vals, func, nhash))
1605
       return EINA_FALSE;
1606

1607
   EINA_LIST_FOREACH(cl->methods, l, func)
1608
     if (!_validate_function(vals, func, nhash))
1609
       return EINA_FALSE;
1610

1611
   EINA_LIST_FOREACH(cl->events, l, event)
1612
     if (!_validate_event(vals, event, ehash))
1613
       return EINA_FALSE;
1614

1615
   EINA_LIST_FOREACH(cl->parts, l, part)
1616
     if (!_validate_part(vals, part, phash))
1617
       return EINA_FALSE;
1618

1619
   EINA_LIST_FOREACH(cl->implements, l, impl)
1620
     if (!_validate_implement(vals, impl))
1621
       return EINA_FALSE;
1622

1623
   /* all the checks that need to be done every time are performed now */
1624
   if (valid)
1625
     {
1626
        /* no need to go through this next time */
1627
        eina_hash_add(chash, &cl, cl);
1628
        return EINA_TRUE;
1629
     }
1630

1631
   if (!_validate_doc(cl->doc))
1632
     return EINA_FALSE;
1633

1634
   /* also done */
1635
   eina_hash_add(chash, &cl, cl);
1636

1637
   return _validate(&cl->base);
1638
}
1639

1640
static Eina_Bool
1641
_validate_constant(Validate_State *vals, Eolian_Constant *var)
1642
{
1643
   if (var->base.validated)
1644
     return EINA_TRUE;
1645

1646
   const char *old_since = vals->since_ver;
1647
   vals->since_ver = NULL;
1648

1649
   Eina_Bool was_stable = _set_stable(vals, !var->base.is_beta && vals->stable);
1650

1651
   if (!_validate_doc_since(vals, var->doc))
1652
     return EINA_FALSE;
1653

1654
   if (!_validate_type(vals, var->base_type, EINA_FALSE, EINA_FALSE))
1655
     return _reset_stable(vals, was_stable, EINA_FALSE);
1656

1657
   if (!_validate_expr(var->value, var->base_type, 0, EINA_FALSE))
1658
     return _reset_stable(vals, was_stable, EINA_FALSE);
1659

1660
   if (!_validate_doc(var->doc))
1661
     return _reset_stable(vals, was_stable, EINA_FALSE);
1662

1663
   _reset_stable(vals, was_stable, EINA_TRUE);
1664
   vals->since_ver = old_since;
1665
   return _validate(&var->base);
1666
}
1667

1668
static Eina_Bool
1669
_typedecl_map_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED,
1670
                 Eolian_Typedecl *tp, Cb_Ret *sc)
1671
{
1672
   return (sc->succ = _validate_typedecl(sc->vals, tp));
1673
}
1674

1675
static Eina_Bool
1676
_constant_map_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED,
1677
             Eolian_Constant *var, Cb_Ret *sc)
1678
{
1679
   return (sc->succ = _validate_constant(sc->vals, var));
1680
}
1681

1682
Eina_Bool
1683
database_validate(const Eolian_Unit *src)
1684
{
1685
   Eolian_Class *cl;
1686

1687
   Validate_State vals = {
1688
      EINA_FALSE,
1689
      EINA_TRUE,
1690
      !!getenv("EFL_RUN_IN_TREE"),
1691
      !!getenv("EOLIAN_CLASS_UNIMPLEMENTED_BETA_WARN"),
1692
   };
1693

1694
   /* do an initial pass to refill inherits */
1695
   Eina_Iterator *iter = eolian_unit_classes_get(src);
1696
   Eina_Hash *fhash = eina_hash_pointer_new(NULL);
1697
   /* keeps track of impls we already errored on to reduce verbosity */
1698
   Eina_Hash *errh = eina_hash_pointer_new(NULL);
1699
   EINA_ITERATOR_FOREACH(iter, cl)
1700
     {
1701
        /* clear, because otherwise if unrelated classes A and B both
1702
         * had interface C in extensions list without implementing it,
1703
         * it would only get printed for A
1704
         */
1705
        eina_hash_free_buckets(errh);
1706
        if (!_db_fill_inherits(&vals, cl, fhash, errh))
1707
          {
1708
             eina_hash_free(errh);
1709
             eina_hash_free(fhash);
1710
             return EINA_FALSE;
1711
          }
1712
     }
1713
   eina_hash_free(errh);
1714
   eina_hash_free(fhash);
1715
   eina_iterator_free(iter);
1716

1717
   iter = eolian_unit_classes_get(src);
1718
   Eina_Hash *nhash = eina_hash_pointer_new(NULL);
1719
   Eina_Hash *ehash = eina_hash_pointer_new(NULL);
1720
   Eina_Hash *phash = eina_hash_pointer_new(NULL);
1721
   Eina_Hash *chash = eina_hash_pointer_new(NULL);
1722
   EINA_ITERATOR_FOREACH(iter, cl)
1723
     {
1724
        eina_hash_free_buckets(nhash);
1725
        eina_hash_free_buckets(ehash);
1726
        eina_hash_free_buckets(phash);
1727
        eina_hash_free_buckets(chash);
1728
        if (!_validate_class(&vals, cl, nhash, ehash, phash, chash))
1729
          {
1730
             eina_iterator_free(iter);
1731
             eina_hash_free(nhash);
1732
             eina_hash_free(ehash);
1733
             eina_hash_free(phash);
1734
             eina_hash_free(chash);
1735
             return EINA_FALSE;
1736
          }
1737
     }
1738
   eina_hash_free(chash);
1739
   eina_hash_free(phash);
1740
   eina_hash_free(ehash);
1741
   eina_hash_free(nhash);
1742
   eina_iterator_free(iter);
1743

1744
   Cb_Ret rt = { &vals, EINA_TRUE };
1745

1746
   eina_hash_foreach(src->aliases, (Eina_Hash_Foreach)_typedecl_map_cb, &rt);
1747
   if (!rt.succ)
1748
     return EINA_FALSE;
1749

1750
   eina_hash_foreach(src->structs, (Eina_Hash_Foreach)_typedecl_map_cb, &rt);
1751
   if (!rt.succ)
1752
     return EINA_FALSE;
1753

1754
   eina_hash_foreach(src->enums, (Eina_Hash_Foreach)_typedecl_map_cb, &rt);
1755
   if (!rt.succ)
1756
     return EINA_FALSE;
1757

1758
   eina_hash_foreach(src->constants, (Eina_Hash_Foreach)_constant_map_cb, &rt);
1759
   if (!rt.succ)
1760
     return EINA_FALSE;
1761

1762
   if(vals.warned)
1763
     return EINA_FALSE;
1764

1765
   return EINA_TRUE;
1766
}
1767

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.