This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch edje-vector-intergration
in repository efl.

View the commit online.

commit b2194d02874642904b61fcdb9c4d5127c4c2df60
Author: [email protected] <[email protected]>
AuthorDate: Thu Apr 30 09:29:05 2026 -0600

    edje: add cross-description vector diagnostics (Task 7.4)
    
    Emit VEC007 (info) and VEC009 (warning) diagnostics at end-of-compile to
    catch type inconsistencies across vector descriptions. VEC007 notes that
    Lottie descriptions skip deep introspection (VEC004/009/010 checks).
    VEC009 pairs descriptions of the same VECTOR part, comparing named node
    types via DFS — warns if a node has different type across descriptions
    (e.g. shape vs container).
    
    Consolidate _node_type_str into shared edje_vg_node_type_str (header +
    edje_cc_handlers.c) to eliminate duplication between handlers and
    diagnostics reporting.
    
    Defer VEC008 (override target unresolvability) — Phase 4.3 VEC002 errors
    already subsume this case. Defer VEC010 (parent-path mismatch) — requires
    ancestor-stack walker; low priority for Phase 7.
    
    Add tests: VEC007 positive, VEC009 trigger, VEC009 negative control.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
---
 src/bin/edje/edje_cc.h                   |   4 +
 src/bin/edje/edje_cc_handlers.c          |  12 +-
 src/bin/edje/edje_cc_out.c               | 163 +++++++++++++++++++++++++++
 src/tests/edje/edje_test_vector_states.c | 186 +++++++++++++++++++++++++++++++
 4 files changed, 359 insertions(+), 6 deletions(-)

diff --git a/src/bin/edje/edje_cc.h b/src/bin/edje/edje_cc.h
index ea8a376a76..24e0b6a87d 100644
--- a/src/bin/edje/edje_cc.h
+++ b/src/bin/edje/edje_cc.h
@@ -328,6 +328,10 @@ Eina_List *_edje_cc_vg_all_trees_get(void);
 Eina_Hash *_edje_cc_vg_desc_to_tree_get(void);
 void       _edje_cc_vg_cleanup(void);
 
+/* Shared node-type label used by VEC diagnostics in both edje_cc_handlers.c
+ * and edje_cc_out.c. Returns "?" for unrecognised values. */
+const char *edje_vg_node_type_str(Edje_Vg_Node_Type type);
+
 void script_rewrite(Code *code);
 
 /* global vars */
diff --git a/src/bin/edje/edje_cc_handlers.c b/src/bin/edje/edje_cc_handlers.c
index f80a843e04..79df0860d3 100644
--- a/src/bin/edje/edje_cc_handlers.c
+++ b/src/bin/edje/edje_cc_handlers.c
@@ -661,7 +661,6 @@ static void       _vg_inline_block_end(void);
 static void       _vg_open_override(Edje_Vg_Node_Type type);
 static void       _vg_close_block(void);
 static void       st_vg_override_target(void);
-static const char *_node_type_str(Edje_Vg_Node_Type t);
 static void       _vg_finalize_description_overrides(void);
 
 static void       ob_collections_group_programs_program(void);
@@ -2039,9 +2038,10 @@ _vg_close_block(void)
      }
 }
 
-/* Task 4.3: Map a node type to a printable string for VEC002 diagnostics. */
-static const char *
-_node_type_str(Edje_Vg_Node_Type t)
+/* Map a node type to a printable string for VEC diagnostics.
+ * Shared across edje_cc_handlers.c and edje_cc_out.c (declared in edje_cc.h). */
+const char *
+edje_vg_node_type_str(Edje_Vg_Node_Type t)
 {
    switch (t)
      {
@@ -2093,8 +2093,8 @@ _vg_finalize_description_overrides(void)
           error_and_abort(NULL,
              "vector override target '%s' is type %s but override expects %s (VEC002)",
              ovr->target_name,
-             _node_type_str(node->type),
-             _node_type_str(ovr->expected_type));
+             edje_vg_node_type_str(node->type),
+             edje_vg_node_type_str(ovr->expected_type));
      }
 }
 
diff --git a/src/bin/edje/edje_cc_out.c b/src/bin/edje/edje_cc_out.c
index 0396d821ad..3945e3d586 100644
--- a/src/bin/edje/edje_cc_out.c
+++ b/src/bin/edje/edje_cc_out.c
@@ -3022,6 +3022,166 @@ data_write_color_class_register(Eet_File *ef)
    free(cc_info);
 }
 
+/* =========================================================================
+ * Task 7.4: Cross-description vector diagnostics (VEC007, VEC009)
+ *
+ * VEC007 (INFO)  — Lottie-source description; topology checks skipped.
+ * VEC009 (WARN)  — same-named nodes have different types across descriptions.
+ * VEC010         — deferred: parent-path mismatch; rare in practice, helper
+ *                  to compute parent-path strings is non-trivial. Noted for
+ *                  Phase 8 polish.
+ * VEC008         — deferred: subsumed by Phase 4.3's VEC002 error.
+ * ========================================================================= */
+
+
+/* Recursive walk over tree A's nodes; for each named node also present in
+ * tree B, check whether the types match.  Emit VEC009 on mismatch. */
+static void
+_vec009_walk(const Edje_Vg_Node *na, const Edje_Vg_Tree *tb,
+             const char *part_name,
+             const char *state_a, const char *state_b)
+{
+   if (!na) return;
+
+   if (na->name)
+     {
+        Edje_Vg_Node *nb = _edje_vg_tree_node_by_name(tb, na->name);
+        if (nb && nb->type != na->type)
+          {
+             edje_diag_emit("VEC009", EDJE_DIAG_WARN, NULL, 0,
+                            part_name, NULL,
+                            "node \"%s\" has different types across descriptions "
+                            "\"%s\" (%s) and \"%s\" (%s) — transition will step "
+                            "instead of interpolating",
+                            na->name,
+                            state_a, edje_vg_node_type_str(na->type),
+                            state_b, edje_vg_node_type_str(nb->type));
+          }
+     }
+
+   if (na->type == EDJE_VG_NODE_CONTAINER)
+     {
+        Eina_List *l;
+        Edje_Vg_Node *child;
+        EINA_LIST_FOREACH(na->container.children, l, child)
+          _vec009_walk(child, tb, part_name, state_a, state_b);
+     }
+}
+
+/* Check one pair of descriptions for VEC009 type mismatches.
+ * tree_a/tree_b are the base trees (overrides not applied — documented
+ * simplification: applying overrides at compile time would require
+ * duplication; base-tree comparison is the pragmatic v1 approach). */
+static void
+_vec009_check_pair(const Edje_Vg_Tree *tree_a, const Edje_Vg_Tree *tree_b,
+                   const char *part_name,
+                   const char *state_a, const char *state_b)
+{
+   /* Walk A→B only: type mismatch is symmetric, so one direction catches
+    * all pairs where the name exists in both trees. */
+   _vec009_walk(tree_a->root, tree_b, part_name, state_a, state_b);
+}
+
+/* Validate all VECTOR descriptions in a single part. */
+static void
+_vec_check_part_descriptions(const Edje_Part_Collection *pc,
+                              const Edje_Part *ep)
+{
+   unsigned int i, j;
+   char state_a[128], state_b[128];
+
+   /* Collect pointers to all descriptions (default + other[]). */
+   unsigned int n = 1 + ep->other.desc_count;
+   Edje_Part_Description_Vector **descs =
+      alloca(n * sizeof(Edje_Part_Description_Vector *));
+
+   descs[0] = (Edje_Part_Description_Vector *)ep->default_desc;
+   for (i = 0; i < ep->other.desc_count; i++)
+     descs[i + 1] = (Edje_Part_Description_Vector *)ep->other.desc[i];
+
+   /* VEC007: info for every Lottie-source description when the part has
+    * more than one description (single-description parts have no
+    * cross-description concern). */
+   if (n > 1)
+     {
+        for (i = 0; i < n; i++)
+          {
+             const Edje_Part_Description_Vector *d = descs[i];
+             if (d->vg.set && d->vg.type == EDJE_VECTOR_FILE_TYPE_LOTTIE)
+               {
+                  snprintf(state_a, sizeof(state_a), "%s %.2f",
+                           d->common.state.name ? d->common.state.name : "default",
+                           d->common.state.value);
+                  edje_diag_emit("VEC007", EDJE_DIAG_INFO, NULL, 0,
+                                 ep->name, state_a,
+                                 "Lottie source — topology / type / parent-path "
+                                 "checks (VEC004/009/010) are skipped for this "
+                                 "description; use SVG inline trees for full "
+                                 "cross-description validation");
+               }
+          }
+     }
+
+   /* VEC009: walk all pairs of tree-based descriptions. */
+   if (!edje_file->vector_dir) return;
+
+   for (i = 0; i < n; i++)
+     {
+        const Edje_Part_Description_Vector *da = descs[i];
+        if (da->vg.tree_id < 0) continue;
+        if ((unsigned int)da->vg.tree_id >= edje_file->vector_dir->trees_count)
+          continue;
+
+        snprintf(state_a, sizeof(state_a), "%s %.2f",
+                 da->common.state.name ? da->common.state.name : "default",
+                 da->common.state.value);
+
+        for (j = i + 1; j < n; j++)
+          {
+             const Edje_Part_Description_Vector *db = descs[j];
+             if (db->vg.tree_id < 0) continue;
+             if ((unsigned int)db->vg.tree_id >= edje_file->vector_dir->trees_count)
+               continue;
+
+             snprintf(state_b, sizeof(state_b), "%s %.2f",
+                      db->common.state.name ? db->common.state.name : "default",
+                      db->common.state.value);
+
+             const Edje_Vg_Tree *ta =
+                &edje_file->vector_dir->trees[da->vg.tree_id];
+             const Edje_Vg_Tree *tb =
+                &edje_file->vector_dir->trees[db->vg.tree_id];
+
+             _vec009_check_pair(ta, tb, ep->name, state_a, state_b);
+          }
+     }
+
+   (void)pc; /* pc available if future checks need collection context */
+}
+
+/* Orchestrator: walk all collections and all VECTOR parts. Called from
+ * data_write() after data_write_vectors_trees() has patched tree_id fields
+ * into descriptions and edje_file->vector_dir is populated. */
+static void
+data_validate_vectors(void)
+{
+   Edje_Part_Collection *pc;
+   Eina_List *l;
+
+   EINA_LIST_FOREACH(edje_collections, l, pc)
+     {
+        unsigned int i;
+        for (i = 0; i < pc->parts_count; i++)
+          {
+             Edje_Part *ep = pc->parts[i];
+             if (ep->type != EDJE_PART_TYPE_VECTOR) continue;
+             /* Skip parts with no non-default descriptions — nothing to compare. */
+             if (!ep->default_desc) continue;
+             _vec_check_part_descriptions(pc, ep);
+          }
+     }
+}
+
 void
 data_write(void)
 {
@@ -3093,6 +3253,9 @@ data_write(void)
       data_write_vectors_trees(ef, &tree_num);
       INF("Wrote %i vector trees", tree_num);
    }
+   /* Task 7.4: cross-description diagnostics — runs after tree_id fields
+    * are patched but before eet_close / vg_cleanup. */
+   data_validate_vectors();
    data_write_groups(ef, &collection_num);
    INF("groups: %3.5f", ecore_time_get() - t); t = ecore_time_get();
    data_write_scripts(ef);
diff --git a/src/tests/edje/edje_test_vector_states.c b/src/tests/edje/edje_test_vector_states.c
index fc25a558a2..a313a9e3f2 100644
--- a/src/tests/edje/edje_test_vector_states.c
+++ b/src/tests/edje/edje_test_vector_states.c
@@ -2081,6 +2081,188 @@ EFL_START_TEST(edje_vg_diag_vec014_inherit_allowed)
 }
 EFL_END_TEST
 
+/* =========================================================================
+ * Phase 7.4: VEC007 and VEC009 cross-description diagnostic tests
+ * ========================================================================= */
+
+/* VEC007 — Lottie-source description on a multi-description part: info fires,
+ * compilation succeeds (zero exit).
+ *
+ * The test creates a fake .json file in /tmp (Lottie files are embedded as
+ * raw bytes so no parsing is required), then compiles an EDC with two
+ * descriptions referencing it and checks VEC007 appears in the output. */
+EFL_START_TEST(edje_vg_diag_vec007_lottie_info)
+{
+   /* Create a minimal fake Lottie JSON in /tmp.  Lottie files are stored as
+    * raw bytes by edje_cc so their content is irrelevant for compilation. */
+   const char *json_name = "edje_diag_vec007_fake.json";
+   char json_path[PATH_MAX];
+   snprintf(json_path, sizeof(json_path), "/tmp/%s", json_name);
+
+   FILE *jf = fopen(json_path, "w");
+   fail_if(!jf);
+   fputs("{\"v\":\"5.6\",\"fr\":30,\"ip\":0,\"op\":30,\"w\":100,\"h\":100,"
+         "\"nm\":\"test\",\"ddd\":0,\"assets\":[],\"layers\":[]}", jf);
+   fclose(jf);
+
+   static const char edc_tmpl[] =
+      "images { vector: \"edje_diag_vec007_fake.json\"; }\n"
+      "collections {\n"
+      "   group { name: \"g\";\n"
+      "      parts {\n"
+      "         part { name: \"v\"; type: VECTOR;\n"
+      "            description { state: \"default\" 0.0;\n"
+      "               image { normal: \"edje_diag_vec007_fake.json\"; }\n"
+      "            }\n"
+      "            description { state: \"alt\" 0.0;\n"
+      "               image { normal: \"edje_diag_vec007_fake.json\"; }\n"
+      "            }\n"
+      "         }\n"
+      "      }\n"
+      "   }\n"
+      "}\n";
+
+   char edc_path[PATH_MAX];
+   snprintf(edc_path, sizeof(edc_path), "/tmp/edje_diag_vec007_%d.edc",
+            (int)getpid());
+   FILE *f = fopen(edc_path, "w");
+   fail_if(!f);
+   fputs(edc_tmpl, f);
+   fclose(f);
+
+   char cmd[PATH_MAX * 4];
+   snprintf(cmd, sizeof(cmd),
+            "EFL_RUN_IN_TREE=1 %s -beta -fd /tmp -id /tmp '%s' /dev/null 2>&1",
+            _EDJE_CC_BIN, edc_path);
+
+   FILE *p = popen(cmd, "r");
+   fail_if(!p);
+
+   char buf[4096];
+   Eina_Bool found = EINA_FALSE;
+   while (fgets(buf, sizeof(buf), p))
+     {
+        if (strstr(buf, "VEC007"))
+          found = EINA_TRUE;
+     }
+
+   int exit_status = pclose(p);
+   unlink(edc_path);
+   unlink(json_path);
+
+   ck_assert_msg(found,
+                 "VEC007 info should be emitted for Lottie-source descriptions");
+   /* VEC007 is INFO — compilation must succeed. */
+   ck_assert_msg(exit_status == 0,
+                 "Compilation should succeed (VEC007 is INFO severity)");
+}
+EFL_END_TEST
+
+/* VEC009 — two descriptions where the same node name has different types:
+ * warning fires, compilation succeeds (zero exit). */
+EFL_START_TEST(edje_vg_diag_vec009_type_mismatch)
+{
+   /* Desc "default" has a shape named "body"; desc "alt" has a container
+    * named "body".  VEC009 must fire as a warning (exit 0). */
+   static const char edc[] =
+      "collections {\n"
+      "   vectors {\n"
+      "      vector { name: \"t1\";\n"
+      "         shape { name: \"body\"; path: \"M0,0 L10,10\";\n"
+      "                 fill.color: 200 0 0 255; }\n"
+      "      }\n"
+      "      vector { name: \"t2\";\n"
+      "         container { name: \"body\"; }\n"
+      "      }\n"
+      "   }\n"
+      "   group { name: \"g\";\n"
+      "      parts {\n"
+      "         part { name: \"v\"; type: VECTOR;\n"
+      "            description { state: \"default\" 0.0;\n"
+      "               vector.use: \"t1\";\n"
+      "            }\n"
+      "            description { state: \"alt\" 0.0;\n"
+      "               vector.use: \"t2\";\n"
+      "            }\n"
+      "         }\n"
+      "      }\n"
+      "   }\n"
+      "}\n";
+
+   ck_assert_msg(_compile_with_diag(edc, "VEC009", EINA_FALSE),
+                 "VEC009 (node type mismatch across descriptions) should warn "
+                 "(zero exit)");
+}
+EFL_END_TEST
+
+/* VEC009 positive control — two descriptions with the same-named node of the
+ * same type: no VEC009 fires, compilation clean (zero exit). */
+EFL_START_TEST(edje_vg_diag_vec009_no_false_positive)
+{
+   /* Both "default" and "alt" have a shape named "body" — types match,
+    * no VEC009 should fire. */
+   static const char edc[] =
+      "collections {\n"
+      "   vectors {\n"
+      "      vector { name: \"ta\";\n"
+      "         shape { name: \"body\"; path: \"M0,0 L10,10\";\n"
+      "                 fill.color: 200 0 0 255; }\n"
+      "      }\n"
+      "      vector { name: \"tb\";\n"
+      "         shape { name: \"body\"; path: \"M5,5 L15,15\";\n"
+      "                 fill.color: 0 0 200 255; }\n"
+      "      }\n"
+      "   }\n"
+      "   group { name: \"g\";\n"
+      "      parts {\n"
+      "         part { name: \"v\"; type: VECTOR;\n"
+      "            description { state: \"default\" 0.0;\n"
+      "               vector.use: \"ta\";\n"
+      "            }\n"
+      "            description { state: \"alt\" 0.0;\n"
+      "               vector.use: \"tb\";\n"
+      "            }\n"
+      "         }\n"
+      "      }\n"
+      "   }\n"
+      "}\n";
+
+   /* Write and compile; expect zero exit and NO VEC009 in output. */
+   char edc_path[PATH_MAX];
+   snprintf(edc_path, sizeof(edc_path),
+            "/tmp/edje_diag_vec009_ok_%d.edc", (int)getpid());
+   FILE *f = fopen(edc_path, "w");
+   fail_if(!f);
+   fputs(edc, f);
+   fclose(f);
+
+   char cmd[PATH_MAX * 2];
+   snprintf(cmd, sizeof(cmd),
+            "EFL_RUN_IN_TREE=1 %s -beta -fd /tmp '%s' /dev/null 2>&1",
+            _EDJE_CC_BIN, edc_path);
+
+   FILE *p = popen(cmd, "r");
+   fail_if(!p);
+
+   char buf[4096];
+   Eina_Bool spurious = EINA_FALSE;
+   while (fgets(buf, sizeof(buf), p))
+     {
+        if (strstr(buf, "VEC009"))
+          spurious = EINA_TRUE;
+     }
+
+   int exit_status = pclose(p);
+   unlink(edc_path);
+
+   ck_assert_msg(exit_status == 0,
+                 "VEC009 positive control: compilation should succeed");
+   ck_assert_msg(!spurious,
+                 "VEC009 positive control: no VEC009 should fire when node "
+                 "types match across descriptions");
+}
+EFL_END_TEST
+
 void
 edje_test_vector_states(TCase *tc)
 {
@@ -2126,4 +2308,8 @@ edje_test_vector_states(TCase *tc)
    /* Phase 7.3 VEC014 transform-form mutual exclusion */
    tcase_add_test(tc, edje_vg_diag_vec014_transform_conflict);
    tcase_add_test(tc, edje_vg_diag_vec014_inherit_allowed);
+   /* Phase 7.4 cross-description diagnostics */
+   tcase_add_test(tc, edje_vg_diag_vec007_lottie_info);
+   tcase_add_test(tc, edje_vg_diag_vec009_type_mismatch);
+   tcase_add_test(tc, edje_vg_diag_vec009_no_false_positive);
 }

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to