Skip to content

Conversation

@MatthewKhouzam
Copy link
Contributor

@MatthewKhouzam MatthewKhouzam commented Dec 5, 2025

What it does

image Support LTTng 2.14.3 CTF 2 traces in trace compass.

How to test

Try to open eclipse-tracecompass/tracecompass-test-traces#12 the traces there

Follow-ups

Review checklist

  • As an author, I have thoroughly tested my changes and carefully followed the instructions in this template

Summary by CodeRabbit

  • New Features
    • Broader JSON/CTF2 metadata support: static/dynamic-length strings & arrays, extended float types, encodings, alias expansion, environment metadata propagation, new string value type, role-based struct access, and improved variant lookups.
  • Bug Fixes
    • Improved duplicate-definition and null-safety checks, safer lookup propagation, removal of a fixed blob size cap, and more robust JSON parsing and integer mapping resolution.
  • Tests
    • Added integration and unit tests for JSON/CTF2 parsing and metadata handling.
  • Version Update
    • Bundle version bumped to 5.1.0.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 5, 2025

📝 Walkthrough

Walkthrough

Bumps bundle version and adds extensive JSON TSdl support: Gson-based metadata parsing with alias expansion, many JSON-aware parsers (strings, arrays, floats, structs), role-aware struct/variant lookups, interval-based integer mappings, new string/blob declarations, trace environment propagation, and multiple tests.

Changes

Cohort / File(s) Summary
Version Update
ctf/org.eclipse.tracecompass.ctf.core/META-INF/MANIFEST.MF
Bumped Bundle-Version 5.0.2.qualifier → 5.1.0.qualifier.
Metadata core & JSON utils
ctf/.../Metadata.java, ctf/.../JsonMetadataStrings.java, ctf/.../JsonTraceMetadataNode.java, ctf/.../IOStructGen.java, ctf/.../tests/META-INF/MANIFEST.MF
Add Gson-based parsing, second-pass alias expansion (expandAliases), JSON metadata constants and encodings map, switch trace environment to JsonObject and populate CTFTrace, add com.google.gson to test manifests.
TSdl routing & parsers
.../TypeAliasParser.java, .../tsdl/staticstring/StaticLengthStringParser.java, .../dynamicstring/DynamicLengthStringParser.java, .../tsdl/staticarray/StaticLengthArrayParser.java, .../tsdl/dynamicarray/DynamicLengthArrayParser.java, .../floatingpoint/FloatDeclarationParser.java, .../tsdl/struct/StructParser.java
Route JSON field-class types in TypeAliasParser; add static/dynamic string & array parsers, JSON-aware float parsing, and JSON struct/member handling.
Declaration registration & struct parsing
ctf/.../DeclarationScope.java, ctf/.../StructDeclarationParser.java, ctf/.../StructDeclaration.java
Add null/empty-name guards, null-safe equality checks, duplicate-field detection, and role support with fRoles, setRole/getRole.
Definitions & lookup behavior
ctf/.../ScopedDefinition.java, ctf/.../StructDefinition.java, ctf/.../VariantDefinition.java
Add exclusion-aware lookup overloads, propagate exclusion during recursion, add role-based short-circuits and recursive role traversal for nested scoped lookups.
String & blob handling
ctf/.../StringDefinition2.java, ctf/.../DynamicLengthStringDeclaration.java, ctf/.../StaticLengthStringDeclaration.java, ctf/.../BlobDeclaration.java
Add StringDefinition2; add static/dynamic-length string declarations with encoding support; remove fixed 1MB pre-check in BlobDeclaration (maximum now derived from length).
Variant internals
ctf/.../VariantDeclaration.java, ctf/.../VariantDefinition.java
Cache field declarations in array (fFieldArray), update variant resolution to use integer/enum tag branches, change fTagDef type, add exclusion-aware lookup method.
Integer mapping & definition
ctf/.../IntegerDeclaration.java, ctf/.../IntegerDefinition.java
Switch mappings to TreeMap, add interval-tree (IntervalNode) for range lookups and binary-search resolution, expose package-private mapping lookup, and make IntegerDefinition lazily resolve/cache mapping strings.
Parser integrations & validations
ctf/.../tsdl/integer/IntegerDeclarationParser.java, ctf/.../tsdl/variant/VariantParser.java, ctf/.../tsdl/struct/StructParser.java, ctf/.../tsdl/struct/StructDeclarationParser.java
Adjust integer creation args, accept IntegerDeclaration as variant tag type, add JSON struct/member handling, and strengthen duplicate/null-declaration checks.
TMF integration
ctf/.../CtfTmfEventField.java
Add handling for StringDefinition2 when constructing TMF CTF string fields.
IO / Trace environment
ctf/.../IOStructGen.java, ctf/.../JsonTraceMetadataNode.java
Populate CTFTrace environment map from Gson JsonObject; switch node environment type to JsonObject.
Tests
ctf/.../tests/CTF2IntegrationTest.java, FloatDeclarationParserTest.java, JsonTraceMetadataNodeTest.java, TypeAliasParserTest.java
Add integration/unit tests for integer mappings, JSON float parsing, trace metadata environment parsing, and TypeAlias/field-class parsing.
Test utilities
common/.../LoggerTest.java
Replace raw log-string assertions with structured JSON-parsing helper assertLogMessage.
Manifests (tests)
common/.../META-INF/MANIFEST.MF, ctf/.../tests/META-INF/MANIFEST.MF
Add com.google.gson to Import-Package in test MANIFEST.MF files.

Sequence Diagram(s)

sequenceDiagram
  participant JSON as JSON metadata (file)
  participant Metadata as Metadata parser
  participant Alias as expandAliases
  participant TypeAlias as TypeAliasParser / field-class parsers
  participant Scope as DeclarationScope
  participant Trace as CTFTrace

  JSON->>Metadata: read fragments (JsonElement per block)
  Metadata->>Alias: collect FIELD_ALIAS entries and expandAliases(map)
  Metadata->>TypeAlias: parse field-class elements -> IDeclaration
  TypeAlias->>Scope: register types / declarations
  Metadata->>Trace: extract JsonObject environment -> setEnvironment(map)
  Note right of Trace: Registered declarations used later for createDefinition
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 I hopped through JSON fields with glee,

aliases unfurled like vines on a tree,
encodings snug, lengths counted fine,
roles and mappings nested in a line,
parsers nibble bytes — the trace tastes like tea.

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Ctf 2 fix draft' is vague and generic. It uses non-descriptive terms ('fix', 'draft') that don't convey the specific nature of the changes, leaving readers unclear about the actual implementation details. Consider revising the title to be more specific and descriptive, such as 'Add CTF 2 trace support with JSON metadata parsing and new string definition types' or similar, to clearly communicate the primary changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@MatthewKhouzam MatthewKhouzam marked this pull request as ready for review December 11, 2025 22:02
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 20

🧹 Nitpick comments (16)
ctf/org.eclipse.tracecompass.ctf.core/META-INF/MANIFEST.MF (1)

5-5: Version bump to 5.1.0.qualifier looks appropriate

Given the additive nature of the CTF core changes described in this PR, moving from 5.0.x to 5.1.0 is consistent with semantic versioning. Please just ensure:

  • Any dependent bundles with tight [5.0.2,5.1.0) ranges are checked/updated if needed.
  • Corresponding release notes/changelog entries are aligned with this new minor version.
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (2)

194-197: Incorrect Javadoc comment for PATH constant.

The Javadoc states "Type string for a structure field class" but PATH = "path" represents a path field location, not a structure type. This appears to be copy-pasted from the STRUCTURE constant below.

-    /**
-     * Type string for a structure field class
-     */
+    /**
+     * Path field within a field-class object
+     */
     public static final String PATH = "path"; //$NON-NLS-1$

240-242: Missing Javadoc comments for MEMBER_CLASSES and MINIMUM_ALIGNMENT.

These constants lack Javadoc comments, which is inconsistent with all other public constants in this file.

+    /**
+     * Member classes of a structure
+     */
     public static final String MEMBER_CLASSES = "member-classes"; //$NON-NLS-1$

+    /**
+     * Minimum alignment of a field class
+     */
     public static final String MINIMUM_ALIGNMENT = "minimum-alignment"; //$NON-NLS-1$
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BlobDeclaration.java (1)

89-95: Javadoc no longer reflects the implementation.

The Javadoc states "Arbitrary decision to have maximum size as 1MB" but the implementation now returns Math.min(fLength, 1000000), which returns the actual length when under 1MB. Consider updating the documentation to clarify the new semantics.

     /**
-     * Arbitrary decision to have maximum size as 1MB
+     * Returns the effective size for this blob, capped at 1MB maximum.
      */
     @Override
     public int getMaximumSize() {
         return Math.min(fLength, 1000000);
     }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java (1)

57-57: Unused param parameter.

The param parameter is declared but never used in the parse method. Consider whether it's needed or if it should be used for validation.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition2.java (1)

34-52: Consider consolidating constructors.

Both constructors have identical implementations, differing only in the declaration parameter type. Since StringDeclaration extends Declaration, the more general constructor (lines 48-52) could handle both cases. Consider if the StringDeclaration-specific constructor is necessary for type safety elsewhere.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDefinition.java (1)

139-164: Significant code duplication between lookupDefinition overloads.

The two lookupDefinition methods share nearly identical logic. Consider extracting common logic to reduce duplication.

Also applies to: 166-192

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java (1)

216-219: Minor style: Consider using role != null for consistency.

The condition null != role (Yoda condition) is functionally correct but less common in this codebase. Consider role != null for consistency.

         String role = declaration.getRole();
-        if(null != role && !role.isEmpty()) {
+        if (role != null && !role.isEmpty()) {
             fRoles.put(role, declaration);
         }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicstring/DynamicLengthStringParser.java (1)

57-57: Unused param parameter.

The param parameter is declared but never used. If the Param class is intended for future use, consider documenting that; otherwise, this creates unnecessary API surface.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (3)

70-72: Use integer literal instead of scientific notation.

The comparison uses 1e6 (floating-point scientific notation) for an integer bound check. Use an integer literal for clarity.

Apply this diff:

-        if (rawLength > 1e6) {
-            throw new CTFException("Cannot have a length > 1000000, declared = " + rawLength); //$NON-NLS-1$
+        if (rawLength > 1_000_000) {
+            throw new CTFException("Cannot have a length > 1,000,000, declared = " + rawLength); //$NON-NLS-1$
         }

73-77: Optimize byte reading using BitBuffer.get(byte[]).

Reading bytes one-by-one in a loop is inefficient. BitBuffer provides a get(byte[] dst) method that reads multiple bytes at once.

Apply this diff:

         int length = (int) rawLength;
         byte[] bytes = new byte[length];
-        for (int i = 0; i < length; i++) {
-            bytes[i] = (byte) input.get(Byte.SIZE, false);
-        }
+        input.get(bytes);
         String value = new String(bytes, fEncoding);

101-105: Incomplete implementation of isBinaryEquivalent.

This method returns false unconditionally with a TODO comment. If binary equivalence checking is needed for static-length strings, this stub will produce incorrect results.

Do you want me to generate a proper implementation or open an issue to track this as a follow-up task?

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/DynamicLengthStringDeclaration.java (4)

76-83: Use an integral literal for the max length bound

1e6 is a double literal; the comparison rawLength > 1e6 performs an implicit widening conversion to double. It works in practice here but is atypical and may trigger static-analysis warnings.

Consider switching to an integral literal:

-        if (rawLength > 1e6) {
+        if (rawLength > 1_000_000L) {
             throw new CTFException("Cannot have a length > 1000000, declared = " + rawLength); //$NON-NLS-1$
         }

This keeps the check purely integral and matches the string literal in the error message.


84-88: Optional: bulk-read bytes and guard with canRead

Functionally, reading each byte via input.get(Byte.SIZE, false) works, but it is a tight per-byte loop and relies on BitBuffer throwing on out-of-bounds. You can make this both clearer and more efficient by checking canRead and using the bulk get(byte[]) API.

Example refactor:

-        byte[] bytes = new byte[length];
-        for (int i = 0; i < length; i++) {
-            bytes[i] = (byte) input.get(Byte.SIZE, false);
-        }
+        if (!input.canRead(length * Byte.SIZE)) {
+            throw new CTFException("Not enough data to read dynamic string of length " + length); //$NON-NLS-1$
+        }
+        byte[] bytes = new byte[length];
+        input.get(bytes);

This assumes alignRead(input) is called earlier (as suggested) so that BitBuffer.get(byte[]) starts on a byte boundary.


101-104: Consider aligning getMaximumSize() with enforced max length

getMaximumSize() returns Integer.MAX_VALUE, but createDefinition enforces rawLength <= 1_000_000. This discrepancy may confuse callers that rely on getMaximumSize() to size buffers or for validation.

If 1_000_000 bytes is the intended hard cap, consider:

  • Either documenting clearly that getMaximumSize() is intentionally looser than the runtime guard, or
  • Adjusting getMaximumSize() to reflect the same bound (in bytes or bits, depending on the contract used elsewhere in the hierarchy).

Please cross-check how other dynamic-length declarations implement getMaximumSize() for consistency.


111-115: Implement isBinaryEquivalent instead of always returning false

Leaving isBinaryEquivalent as a stub that always returns false may break reuse of declarations or type caching logic that depends on binary equivalence checks. For declarations with the same encoding and length-field name, it’s reasonable to treat them as equivalent.

Possible implementation:

     @Override
     public boolean isBinaryEquivalent(IDeclaration other) {
-        // TODO Auto-generated method stub
-        return false;
+        if (this == other) {
+            return true;
+        }
+        if (!(other instanceof DynamicLengthStringDeclaration)) {
+            return false;
+        }
+        DynamicLengthStringDeclaration o = (DynamicLengthStringDeclaration) other;
+        return fEncoding.equals(o.fEncoding) && fLengthName.equals(o.fLengthName);
     }

If you prefer to support subclasses or nullable length names, you can relax the equality check accordingly.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 835eca3 and 99a9d62.

📒 Files selected for processing (21)
  • ctf/org.eclipse.tracecompass.ctf.core/META-INF/MANIFEST.MF (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BlobDeclaration.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/ScopedDefinition.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition2.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java (5 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDeclaration.java (4 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDefinition.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java (4 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicarray/DynamicLengthArrayParser.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicstring/DynamicLengthStringParser.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (2 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/DynamicLengthStringDeclaration.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (6)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicstring/DynamicLengthStringParser.java (1)
  • DynamicLengthStringParser (46-102)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/enumeration/EnumParser.java (1)
  • EnumParser (97-266)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java (1)
  • StaticLengthArrayParser (33-112)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java (1)
  • StaticLengthStringParser (46-102)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (1)
  • StructParser (95-285)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-244)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-244)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (3)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMemberMetadataNode.java (1)
  • JsonStructureFieldMemberMetadataNode (31-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMetadataNode.java (1)
  • JsonStructureFieldMetadataNode (29-89)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-244)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/DynamicLengthStringDeclaration.java (4)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/io/BitBuffer.java (1)
  • BitBuffer (32-743)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/Declaration.java (1)
  • Declaration (30-90)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDefinition.java (1)
  • IntegerDefinition (33-202)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition2.java (1)
  • StringDefinition2 (22-72)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-244)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (3)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/io/BitBuffer.java (1)
  • BitBuffer (32-743)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/Declaration.java (1)
  • Declaration (30-90)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition2.java (1)
  • StringDefinition2 (22-72)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build / build
  • GitHub Check: build / build
🔇 Additional comments (20)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java (2)

38-40: LGTM!

The new imports are appropriate for the JSON element-based parsing and alias expansion functionality.

Also applies to: 78-80


268-291: LGTM!

Using the pre-parsed and alias-expanded JsonElement for all fromJson calls is consistent and ensures the expanded aliases are correctly deserialized.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java (1)

131-135: LGTM!

The updated logic correctly allows re-registration of the same declaration (idempotent behavior) while still detecting actual conflicts where a different declaration is being registered for the same field name. The null checks ensure safe comparison.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java (1)

175-182: LGTM!

Good improvements: early return for null/empty names prevents registering anonymous types, and Objects.equals() provides null-safe comparison for declaration equality.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (1)

172-181: LGTM!

The new type handling cases for dynamic/static length strings, arrays, and structures follow the established parsing pattern consistently. Each parser is invoked with the appropriate parameters.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (1)

192-200: LGTM!

The handling for JsonStructureFieldMetadataNode correctly reads the minimum alignment and member classes, following the established pattern.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java (1)

186-227: LGTM!

The exclusion-aware lookup implementation is well-structured:

  • Early exit for self-exclusion and null path prevents infinite recursion
  • Role-based resolution short-circuits when declaration role matches
  • Recursive calls correctly propagate the exclusion parameter
  • Parent scope delegation appropriately uses this as the exclusion
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDeclaration.java (1)

127-152: LGTM for the two-branch tag resolution logic.

The implementation correctly handles both IntegerDefinition (with mappings or numeric index) and EnumDefinition (with string value lookup) tag types. Error handling is appropriate with informative messages.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition2.java (1)

63-66: size() returns character count, not byte count.

For strings with multi-byte encodings (e.g., UTF-8), fString.length() returns the number of characters, not bytes. If size() is expected to return the byte size (consistent with CTF field sizing), this could lead to incorrect calculations.

Verify whether size() should return the byte count based on the string's encoding, or if character count is intentional here.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDefinition.java (2)

45-69: LGTM for new constructor supporting SimpleDatatypeDefinition.

The new constructor properly initializes the variant definition with the new tag type, enabling support for integer-based variant tags in addition to enum-based ones.


146-151: Potential issue with null role comparison.

getDeclaration().getRole() may return null. Calling lookupPath.equals(null) will always return false, which is safe, but the intent may be clearer with a null check. More critically, if fTagDef or fDefinition could have a null declaration, this would NPE.

Verify that fTagDef.getDeclaration() and fDefinition.getDeclaration() are guaranteed to be non-null.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java (3)

59-60: LGTM for role-based lookup mechanism.

The fRoles map provides an efficient way to look up declarations by their semantic role, which is useful for CTF 2 metadata where roles like "packet-magic-number" or "event-record-id" need to be resolved.


348-352: LGTM for propagating role to self-registration.

This ensures that when a struct has a role assigned, it registers itself in the roles map, enabling proper lookup of nested structures by role.


422-430: LGTM for role accessor.

The getRole(String) method provides clean access to child declarations by role.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicstring/DynamicLengthStringParser.java (1)

77-101: Param class is defined but unused within this parser.

The Param inner class is defined but the parse method doesn't use the param argument. Verify if this is intentional for API consistency with other parsers or if it should be removed.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicarray/DynamicLengthArrayParser.java (2)

78-114: LGTM!

The Param inner class is well-structured with proper encapsulation and clear accessors.


72-73: Verify that empty string parameters are safe for element node creation.

The JsonStructureFieldMemberMetadataNode is created with empty strings for the name, role, and other parameters. Ensure that TypeAliasParser and downstream code correctly handle these empty values without assuming they contain meaningful identifiers.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java (2)

75-111: LGTM!

The Param inner class follows the same well-structured pattern as in DynamicLengthArrayParser.


69-70: The empty string parameters are safe and intentional.

The JsonStructureFieldMemberMetadataNode created with empty strings at lines 69-70 is a synthetic element node for array elements. TypeAliasParser.parse() explicitly handles this case: when the node's type is empty (line 143 of TypeAliasParser), it extracts the actual type from the field class JSON object. This same pattern is identically used in DynamicLengthArrayParser, confirming it is intentional design. No changes needed.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/DynamicLengthStringDeclaration.java (1)

25-94: Overall logic of dynamic string decoding looks solid

Aside from the points above (nullability, alignment, and minor style/robustness concerns), the core flow—lookup of a length field, validation, bounded read, charset-based decoding, and trimming at the first '\0'—is clear and matches the intended semantics for a length-prefixed, null-terminated string.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BlobDeclaration.java (1)

64-76: Fix broken max-size enforcement (current getMaximumSize() makes the guard ineffective + risks OOM/DoS).

With getMaximumSize() returning fLength * 8 (Line 91), createDefinition()’s check (Line 66) becomes non-protective for non-negative lengths and can also fail via int overflow. This allows huge allocations (new byte[fLength], Line 69) from untrusted trace data.

Suggested direction (keeps “no arbitrary 1MB” while still preventing runaway allocations):

 public class BlobDeclaration extends Declaration {
 
+    private static final int DEFAULT_MAX_BLOB_BYTES =
+            Integer.getInteger("org.eclipse.tracecompass.ctf.maxBlobBytes", 64 * 1024 * 1024);
+
     private final int fLength;
     private final String fMediaType;
@@
     public @NonNull BlobDefinition createDefinition(IDefinitionScope definitionScope, @NonNull String fieldName, @NonNull BitBuffer input) throws CTFException {
+        if (fLength < 0) {
+            throw new CTFException("Negative blob length: " + fLength); //$NON-NLS-1$
+        }
         if (fLength > getMaximumSize()) {
             throw new CTFException("Length asked: " + fLength + " is larger than the maximum blob size " + getMaximumSize()); //$NON-NLS-1$ //$NON-NLS-2$
         }
         byte[] array = new byte[fLength];
@@
     @Override
     public int getMaximumSize() {
-        return fLength*8;
+        return DEFAULT_MAX_BLOB_BYTES;
     }

(If you don’t want a cap at all, then getMaximumSize() should not be derived from fLength, and createDefinition() should still hard-fail on negative lengths to avoid NegativeArraySizeException.)

Also applies to: 89-92

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java (1)

566-577: Critical: hashCode() and equals() contract violation.

The equals() method now includes fMappings and getRole() in equality checks (Lines 603-608), but hashCode() (Lines 566-577) does not include these fields. This violates the Java contract: equal objects must have equal hash codes.

Objects with identical base properties but different mappings/roles will have the same hash code but not be equal, causing incorrect behavior in hash-based collections like HashMap and HashSet.

Add fMappings and role to hashCode():

 @Override
 public int hashCode() {
     final int prime = 31;
     int result = 1;
     result = prime * result + (int) (fAlignment ^ (fAlignment >>> 32));
     result = prime * result + fBase;
     result = prime * result + fByteOrder.toString().hashCode();
     result = prime * result + fClock.hashCode();
     result = prime * result + fEncoding.hashCode();
     result = prime * result + fLength;
     result = prime * result + (fSigned ? 1231 : 1237);
+    result = prime * result + Objects.hashCode(fMappings);
+    result = prime * result + Objects.hashCode(getRole());
     return result;
 }

Also applies to: 603-608

🧹 Nitpick comments (4)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java (2)

172-186: registerType: good idempotency + anonymous-type skip; consider enforcing non-null input contract
Skipping null/empty names (Line 175) avoids polluting the registry with anonymous types, and the Objects.equals comparison (Line 180) enables “same type, re-register is OK” semantics. Main watch-out: this behavior depends on IDeclaration.equals() being well-defined (structural vs reference).


198-206: registerIdentifier: add a guard for null/empty identifier names
Unlike registerType, registerIdentifier will currently accept name == null or name.isEmpty(), which permits null keys in HashMap and can cause hard-to-debug overwrites if the parser ever produces an unnamed identifier. Suggest throwing ParseException (or IllegalArgumentException) early.

 public void registerIdentifier(String name, IDeclaration declaration) throws ParseException {
+    if (name == null || name.isEmpty()) {
+        throw new ParseException("Identifier name is null/empty"); //$NON-NLS-1$
+    }
     /* Check if the type has been defined in the current scope */
     IDeclaration iDeclaration = fIdentifiers.get(name);
     if (iDeclaration != null && !Objects.equals(iDeclaration, declaration)) {
         throw new ParseException("Identifier has already been defined:" + name); //$NON-NLS-1$
     }
     /* Add it to the register. */
     fIdentifiers.put(name, declaration);
 }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BlobDeclaration.java (1)

35-62: Clarify whether len is “bits” or “bytes” (Javadoc vs implementation mismatch).

Constructor docs say “length in bits” (Line 39, 51) but parsing/array allocation treats fLength as bytes (Line 69-73). This will confuse future changes and makes it hard to reason about size limits.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java (1)

188-190: Prefer == for identity comparison.

Using this.equals(defintionToExclude) works but == is more idiomatic and efficient for checking object identity (i.e., same instance). The equals method may be overridden to compare content, which is not the intent here.

-        if (this.equals(defintionToExclude) || lookupPath == null) {
+        if (this == defintionToExclude || lookupPath == null) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 99a9d62 and 361b552.

📒 Files selected for processing (8)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BlobDeclaration.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java (8 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDefinition.java (2 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java (4 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonTraceMetadataNode.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / build
  • GitHub Check: build / build
  • GitHub Check: build / build
🔇 Additional comments (11)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java (1)

20-20: Import addition is fine; keep an eye on equals() coverage
java.util.Objects is now load-bearing for duplicate detection semantics; if any IDeclaration subclasses don’t implement equals() appropriately, this still degenerates to reference-identity checks.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDefinition.java (1)

109-114: Lazy initialization is not thread-safe, but impact is minimal.

Multiple threads calling getMappings() concurrently could compute the mapping redundantly. Since String assignment is atomic and the computation is deterministic, the worst outcome is wasted computation, not incorrect behavior. Consider using volatile or a synchronized block if this is called frequently in multi-threaded contexts.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java (1)

264-269: Good fix: Corrected parameter order for mapped declarations.

The first argument to createDeclaration is now correctly (int) size instead of base, aligning the mapped path (Line 265) with the non-mapped path (Line 268). This fixes a bug where mapped integer declarations would have been created with incorrect bit lengths.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java (2)

549-551: Good improvement: Using Long.SIZE constant.

Replacing the hardcoded 64 with Long.SIZE improves readability and self-documents the intent.


134-146: Interval tree structure is appropriate for the mapping use case.

The IntervalNode inner class and sorted list approach provide a reasonable foundation for mapping lookups. Note that the algorithm using this structure has issues (addressed separately).

Also applies to: 372-387

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java (2)

23-26: LGTM!

The new imports are necessary for the environment propagation logic and are used appropriately.

Also applies to: 52-52


161-162: The current implementation is correct. Environment values from JSON traces are intentionally stored in their JSON representation format (using toString()), and downstream code in LttngUstTrace and LttngKernelTrace explicitly validates against this format by checking for literal "\"ust\"" and "\"kernel\"" strings with escaped quotes included.

Likely an incorrect or invalid review comment.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonTraceMetadataNode.java (1)

19-19: Library migration is complete and properly configured.

The migration from org.json.JSONObject to com.google.gson.JsonObject is consistent across import, field declaration, and getter return type. The @SerializedName annotation is properly supported by Gson, and the dependency is correctly declared in META-INF/MANIFEST.MF under Import-Package. All references in the codebase have been updated, including the usage in IOStructGen.java where getEnvironment().entrySet() is called.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java (3)

205-219: Role-based lookup enhancement looks correct.

The logic properly short-circuits when a child's declaration role matches the lookup path, avoiding unnecessary recursion. The exclusion propagation via defintionToExclude correctly prevents infinite loops in cyclic references.


238-252: Null-safety and recursive traversal additions are correct.

The early return for null role and the delegation to lookupRoleRecursive for nested structures follow a sound pattern.


254-266: Add null check before accessing getCurrentField() result to prevent NullPointerException.

On line 259, getCurrentField() may return null if no field is currently selected. Accessing current.getDeclaration() on line 260 without a null check can cause NPE. Add a guard before dereferencing:

    private IDefinition lookupRoleRecursive(IDefinition def, String role) {
        if (def instanceof StructDefinition) {
            return ((StructDefinition) def).lookupRole(role);
        }
        if (def instanceof VariantDefinition) {
            IDefinition current = ((VariantDefinition) def).getCurrentField();
+            if (current == null) {
+                return null;
+            }
            if (role.equals(current.getDeclaration().getRole())) {
                return current;
            }
            return lookupRoleRecursive(current, role);
        }
        return null;
    }

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java (1)

121-130: Good: StringDefinition2 is now parsed as a TMF string; consider null-safety + dedup.

  • This mirrors the StringDefinition path correctly.
  • Suggestion: defensively handle a potential null value (e.g., map to "") or enforce @NonNull in StringDefinition2 (its size() currently assumes non-null).
  • Optional: collapse the two branches to reduce duplication (e.g., helper parseStringDefinition(...) / common interface).
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 361b552 and bc1f0bc.

📒 Files selected for processing (1)
  • ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition2.java (1)
  • StringDefinition2 (22-72)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build / build
  • GitHub Check: build / build
🔇 Additional comments (1)
ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java (1)

42-43: Import + new type dependency looks fine, but keep the surface area contained.
Since StringDefinition2 is new API in the CTF core, consider whether this file should be the only TMF-side “bridge” for it (vs. sprinkling StringDefinition2 checks in multiple places).

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (1)

144-148: Potential NullPointerException when accessing type from fieldClass.

The call to fieldClass.get(JsonMetadataStrings.TYPE).getAsString() will throw NPE if the TYPE key is absent. Additionally, the fieldClass.isJsonObject() check on line 145 is redundant since fieldClass is already a JsonObject (assigned via getAsJsonObject() on line 113).

Apply this diff to add null safety:

             if (type.isEmpty()) {
-                if (fieldClass.isJsonObject()) {
-                    type = fieldClass.get(JsonMetadataStrings.TYPE).getAsString();
+                JsonElement typeElement = fieldClass.get(JsonMetadataStrings.TYPE);
+                if (typeElement != null && typeElement.isJsonPrimitive()) {
+                    type = typeElement.getAsString();
                 }
             }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bc1f0bc and f760a5b.

📒 Files selected for processing (2)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (5 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / build
  • GitHub Check: build / build
  • GitHub Check: build / build
🔇 Additional comments (2)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (1)

173-186: LGTM!

The new type handling branches follow the established pattern in the file and correctly map each TSdl type to its corresponding parser with appropriate parameters.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)

50-58: LGTM!

The new constants are properly documented and follow the established naming conventions. The string values align with CTF2 specification terminology.

Also applies to: 160-167, 179-192, 224-247

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (3)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (3)

203-206: Incorrect Javadoc for PATH constant.

Already flagged in previous review - the Javadoc incorrectly says "Type string for a structure field class" but the constant represents "path".


220-222: UTF-32 charset JDK compatibility concern.

Already flagged in previous review - Charset.forName("UTF-32BE") and Charset.forName("UTF-32LE") may throw UnsupportedCharsetException on JDKs prior to version 22.


249-251: Missing Javadoc for public constants.

Already flagged in previous review - MEMBER_CLASSES and MINIMUM_ALIGNMENT are missing Javadoc comments.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f760a5b and b6481f5.

📒 Files selected for processing (2)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (2 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (5 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / build
  • GitHub Check: build / build
  • GitHub Check: build / build
🔇 Additional comments (6)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (3)

16-19: LGTM!

Imports are appropriate for the new ENCODINGS map functionality.


50-60: LGTM!

Constants are properly documented with Javadoc and follow the established conventions.


160-168: LGTM!

Floating-point type constants are properly documented and follow the file conventions.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (3)

25-36: LGTM!

Imports are appropriate for the new JSON-based metadata parsing functionality.


133-145: LGTM!

The IEEE 754 size mappings are correct:

  • 32-bit single precision: exponent=8, mantissa=24
  • 64-bit double precision: exponent=11, mantissa=53

Clear error handling for unsupported sizes.


155-192: LGTM!

The legacy parsing branch is well-structured with:

  • Proper null check for children with clear error message
  • Comprehensive handling of all float attributes (exp_dig, byte_order, mant_dig, align)
  • Appropriate error handling for unknown attributes

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (2)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java (1)

19-20: Same blocker as above: Gson missing from test classpath.

(See comment in CTF2IntegrationTest.java about adding Gson to org.eclipse.tracecompass.ctf.core.tests dependencies.)

Also applies to: 24-58

ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java (1)

24-26: Same blocker as above: Gson missing from test classpath.

(See comment in CTF2IntegrationTest.java about adding Gson to org.eclipse.tracecompass.ctf.core.tests dependencies.)

Also applies to: 30-89

🧹 Nitpick comments (4)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java (1)

77-116: Strengthen mapping assertions to validate ranges, not just keys.

testIntegerWithMappings() only checks map keys exist; it won’t catch wrong range parsing. Consider asserting the parsed ranges for "ZERO" and "ONE" are exactly [0,0] and [1,1] (whatever the concrete IntegerDeclaration#getMappings() value type is).

ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java (1)

33-37: Prefer Gson deserialization over reflection to set private fields.

These tests are tightly coupled to private field names (fEnvironment, fUid). If feasible, build JSON and deserialize into JsonTraceMetadataNode with Gson to better match production wiring and reduce brittleness.

Also applies to: 50-54

ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java (1)

30-52: Tighten assertions to validate parsed properties (not just non-null).

For better regression protection, consider asserting key parsed attributes:

  • float: expected length/byte-order-derived properties (or explicit exponent/mantissa expected for 32-bit if stable)
  • strings: length (static case) and encoding for both static/dynamic cases (if accessible from the returned declaration).

Also applies to: 54-71, 73-89

ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java (1)

30-48: Add missing assertion for default alignment in the 32-bit case
FloatDeclarationParser normalizes missing alignment to 1; testCTF2Float32Parsing() should assert it to lock the behavior.

         assertEquals(ByteOrder.LITTLE_ENDIAN, result.getByteOrder());
+        assertEquals(1, result.getAlignment());
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b6481f5 and a278a00.

📒 Files selected for processing (4)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java (4)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java (1)
  • StructDeclaration (49-432)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/CTFTrace.java (1)
  • CTFTrace (81-1043)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMemberMetadataNode.java (1)
  • JsonStructureFieldMemberMetadataNode (31-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java (1)
  • IntegerDeclarationParser (81-271)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonTraceMetadataNode.java (1)
  • JsonTraceMetadataNode (28-87)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java (2)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMemberMetadataNode.java (1)
  • JsonStructureFieldMemberMetadataNode (31-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (1)
  • TypeAliasParser (55-219)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java (2)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMemberMetadataNode.java (1)
  • JsonStructureFieldMemberMetadataNode (31-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (1)
  • FloatDeclarationParser (66-206)
🪛 GitHub Actions: Continuous Integration (core tests only)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java

[error] 1-1: Compilation failed: The type com.google.gson.JsonObject cannot be resolved. Imports for Gson classes (JsonArray, JsonObject, JsonPrimitive) are failing, indicating a missing or unresolved Gson dependency during test compilation.

ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java

[error] 1-1: Compilation failed: com.google.gson.JsonObject, JsonPrimitive cannot be resolved in tests importing Gson classes.

🪛 GitHub Actions: Continuous Integration (long-ui tests only)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java

[error] 1-1: Compilation failed: The type com.google.gson.JsonObject cannot be resolved. Gson dependencies are missing for CTF tests (CTF2IntegrationTest.java).


[error] 1-1: Compilation failed: Import com.google.gson.JsonArray cannot be resolved in CTF2IntegrationTest.java.


[error] 1-1: Compilation failed: Import com.google.gson.JsonPrimitive cannot be resolved in CTF2IntegrationTest.java.


[error] 1-1: The constructor JsonStructureFieldMemberMetadataNode(...) refers to missing type JsonObject (Gson types not resolved).

ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java

[error] 1-1: Compilation failed: The type JsonObject cannot be resolved in JsonTraceMetadataNodeTest.java (imports of Gson types missing).

ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java

[error] 1-1: Compilation failed: Gson-related classes not resolved in TypeAliasParserTest.java.

ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java

[error] 1-1: Compilation failed: Gson types (JsonObject/JsonPrimitive) cannot be resolved in FloatDeclarationParserTest.java.

🪛 GitHub Actions: Continuous Integration (short-ui tests only)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java

[error] 1-1: Compilation failure: The type com.google.gson.JsonObject cannot be resolved. It is indirectly referenced from required type org.eclipse.tracecompass.ctf.core.trace.Metadata. Imports for com.google.gson.JsonArray, com.google.gson.JsonObject, and com.google.gson.JsonPrimitive cannot be resolved.


[error] 1-1: Compilation failure: JsonObject cannot be resolved to a type; JsonArray/JsonPrimitive also unresolved in test code.


[error] 1-1: The constructor JsonStructureFieldMemberMetadataNode(ICTFMetadataNode, String, String, String, JsonObject) refers to the missing type JsonObject.


[error] 1-1: CTF2IntegrationTest contains multiple references to Gson Json* classes (JsonObject, JsonArray, JsonPrimitive) that cannot be resolved due to missing Gson dependency in the test classpath.


[error] 1-1: Compilation failure: Unresolved references to JsonObject/JsonPrimitive in test code; likely due to missing Gson on test classpath.

ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java

[error] 1-1: Compilation failure: JsonObject and JsonPrimitive types used in tests cannot be resolved due to missing Gson dependency.

ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java

[error] 1-1: Compilation failure: Gson JsonObject/JsonPrimitive types cannot be resolved in TypeAliasParserTest.

ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java

[error] 1-1: Compilation failure: The imports for com.google.gson.JsonObject and com.google.gson.JsonPrimitive cannot be resolved.

🔇 Additional comments (1)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java (1)

65-75: Verify API usage: StructDeclaration#getFields() and JsonStructureFieldMemberMetadataNode#setFieldClass(...) may be non-portable.

assertEquals(2, result.getFields().size()) and node.setFieldClass(...) assume APIs that may not exist (or may differ) across versions. If StructDeclaration doesn’t expose getFields(), consider asserting via hasField(...) + iterating getFieldsList() instead. If JsonStructureFieldMemberMetadataNode doesn’t support mutation, construct it with the field-class in the constructor instead.

Comment on lines 34 to 49
JsonObject fieldClass = new JsonObject();
fieldClass.add("length", new JsonPrimitive(32));
fieldClass.add("byte-order", new JsonPrimitive("le"));

JsonStructureFieldMemberMetadataNode node = new JsonStructureFieldMemberMetadataNode(null, "test", "test");
node.setFieldClass(fieldClass);

FloatDeclaration result = FloatDeclarationParser.INSTANCE.parse(node,
new FloatDeclarationParser.Param(trace));

Copy link

@coderabbitai coderabbitai bot Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

CI blocker: JsonStructureFieldMemberMetadataNode is constructed/used with the wrong API
The test uses a 3-arg ctor + setFieldClass(...), but the provided class signature takes (parent, type, value, name, fieldClass) and the field class is final (no setter). This will fail compilation even after fixing Gson.

Suggested fix (also drops unnecessary JsonPrimitive usage):

-        JsonObject fieldClass = new JsonObject();
-        fieldClass.add("length", new JsonPrimitive(32));
-        fieldClass.add("byte-order", new JsonPrimitive("le"));
+        JsonObject fieldClass = new JsonObject();
+        fieldClass.addProperty("length", 32);
+        fieldClass.addProperty("byte-order", "le");

-        JsonStructureFieldMemberMetadataNode node = new JsonStructureFieldMemberMetadataNode(null, "test", "test");
-        node.setFieldClass(fieldClass);
+        JsonStructureFieldMemberMetadataNode node =
+                new JsonStructureFieldMemberMetadataNode(null, "test", "test", "field", fieldClass);

@@
-        JsonObject fieldClass = new JsonObject();
-        fieldClass.add("length", new JsonPrimitive(64));
-        fieldClass.add("byte-order", new JsonPrimitive("be"));
-        fieldClass.add("alignment", new JsonPrimitive(8));
+        JsonObject fieldClass = new JsonObject();
+        fieldClass.addProperty("length", 64);
+        fieldClass.addProperty("byte-order", "be");
+        fieldClass.addProperty("alignment", 8);

-        JsonStructureFieldMemberMetadataNode node = new JsonStructureFieldMemberMetadataNode(null, "test", "test");
-        node.setFieldClass(fieldClass);
+        JsonStructureFieldMemberMetadataNode node =
+                new JsonStructureFieldMemberMetadataNode(null, "test", "test", "field", fieldClass);

Also applies to: 54-64

🤖 Prompt for AI Agents
In
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java
around lines 34-43 (and likewise 54-64), the test constructs
JsonStructureFieldMemberMetadataNode with the old 3-arg ctor and calls
setFieldClass(...) which no longer exists; instead call the current constructor
that accepts (parent, type, value, name, fieldClass) and pass the JsonObject
fieldClass as the fifth argument, and simplify the JsonObject contents by adding
plain primitives (e.g., JsonObject.addProperty("length", 32) and
addProperty("byte-order", "le")) rather than wrapping values in JsonPrimitive.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is better than claude!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MatthewKhouzam, thank you! I'm glad the analysis was helpful. Let me know if you need any clarification on the suggested constructor fix or run into any issues while implementing it. 😊

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java (1)

38-54: Tests look correct; please double-check CTFTrace lifecycle + Gson OSGi import
The updated JsonStructureFieldMemberMetadataNode(..., name, fieldClass) construction matches the newer API and should compile cleanly.

  • Verify whether org.eclipse.tracecompass.ctf.core.trace.CTFTrace needs explicit cleanup (e.g., dispose() / close()) even when instantiated empty in tests.
  • Ensure the test bundle declares Gson as an OSGi import (if not already), since this class directly imports com.google.gson.*.

Also applies to: 62-80

🧹 Nitpick comments (2)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java (1)

24-26: Prefer JsonObject#addProperty(...) over manual JsonPrimitive wrapping
This is more idiomatic Gson and reduces noise in the tests.

-import com.google.gson.JsonPrimitive;
@@
-        fieldClass.add("length", new JsonPrimitive(32));
-        fieldClass.add("byte-order", new JsonPrimitive("le"));
+        fieldClass.addProperty("length", 32);
+        fieldClass.addProperty("byte-order", "le");
@@
-        fieldClass.add("length", new JsonPrimitive(64));
-        fieldClass.add("byte-order", new JsonPrimitive("be"));
-        fieldClass.add("alignment", new JsonPrimitive(8));
+        fieldClass.addProperty("length", 64);
+        fieldClass.addProperty("byte-order", "be");
+        fieldClass.addProperty("alignment", 8);

Also applies to: 41-44, 65-69

ctf/org.eclipse.tracecompass.ctf.core.tests/META-INF/MANIFEST.MF (1)

27-27: LGTM! Gson import added for JSON metadata parsing tests.

The import is correctly placed and necessary for the JSON/TSdl metadata parsing capabilities introduced in this PR.

Optional improvement: Consider adding a version range to the Gson import for better dependency management, e.g., com.google.gson;version="[2.8.0,3.0.0)". This helps ensure compatibility and follows OSGi best practices, though the current approach is consistent with some other imports in this manifest (like com.google.common.collect).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a278a00 and 8cbe6cf.

📒 Files selected for processing (5)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/META-INF/MANIFEST.MF (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java
🧰 Additional context used
🧬 Code graph analysis (1)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonTraceMetadataNode.java (1)
  • JsonTraceMetadataNode (28-87)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / build
  • GitHub Check: build / build
  • GitHub Check: build / build
🔇 Additional comments (1)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java (1)

33-50: Nice: focused assertions on getEnvironment() and getUid() outputs.

The assertions are clear and validate the getters after initialize().

Also applies to: 60-69

Comment on lines +58 to +70
@Test
public void testUidAndPacketHeader() throws Exception {
JsonTraceMetadataNode node = new JsonTraceMetadataNode(null, "trace-class", "test");

// Simulate Gson deserialization
java.lang.reflect.Field uidField = JsonTraceMetadataNode.class.getDeclaredField("fUid");
uidField.setAccessible(true);
uidField.set(node, "test-uid-123");

node.initialize();

assertEquals("test-uid-123", node.getUid());
}
Copy link

@coderabbitai coderabbitai bot Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Test name doesn’t match coverage: no packet header is set/asserted.

testUidAndPacketHeader only asserts getUid(). Either rename to testUidParsing() or actually inject fPacketHeader (with a minimal JsonStructureFieldMetadataNode) and assert initialize() wires it (e.g., getPacketHeader() not null and/or child linkage if accessible).

🤖 Prompt for AI Agents
In
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java
around lines 58 to 70, the test named testUidAndPacketHeader only sets and
asserts the UID but does not set or assert any packet header; either rename the
test to testUidParsing() or modify it to inject a minimal fPacketHeader (create
a JsonStructureFieldMetadataNode instance, set it via reflection like fUid was
set), call initialize(), and add assertions that getPacketHeader() returns
non-null (and optionally verify the child linkage or expected type) to ensure
initialize() wires the packet header correctly.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arfio, thank you for confirming!

Would you like to address this in the current PR by either:

  1. Renaming the test to testUidParsing() to match what it actually tests, or
  2. Adding packet header injection and assertions to truly cover both UID and packet header?

If you prefer to defer this to a follow-up, that works too—just let me know!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8cbe6cf and e76e243.

📒 Files selected for processing (1)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (6)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/CTFJsonMetadataNode.java (1)
  • CTFJsonMetadataNode (33-171)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMemberMetadataNode.java (1)
  • JsonStructureFieldMemberMetadataNode (31-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/AlignmentParser.java (1)
  • AlignmentParser (51-117)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/ByteOrderParser.java (1)
  • ByteOrderParser (53-129)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/UnaryIntegerParser.java (1)
  • UnaryIntegerParser (28-68)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-257)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / build
  • GitHub Check: build / build
  • GitHub Check: build / build
🔇 Additional comments (3)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (3)

25-36: Imports properly support JSON metadata parsing.

The new imports for JSON-based metadata handling are appropriate and necessary for the dual-path (JSON and legacy AST) parsing approach.


133-145: LENGTH-to-exponent/mantissa mapping is correct.

The mapping follows IEEE 754 standard for 32-bit (8 exponent, 24 mantissa) and 64-bit (11 exponent, 53 mantissa) floating-point numbers, with appropriate error handling for unsupported sizes.


155-192: Legacy parsing path properly preserved.

The existing AST-based parsing logic is maintained in the else branch with proper validation and error handling, ensuring backward compatibility while adding JSON support.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (1)

213-220: Redefinition guard is only applied to the non-JSON path; apply the same protection to JSON parsing too.
Right now, JSON-based aliases can still redefine an existing type (or rely on registerType behavior), while the ANTLR path rejects duplicates. Consider moving the lookupType check to just before registerType(...) so both branches are protected consistently.

-        scope.registerType(aliasString, targetDeclaration);
+        if (scope.lookupType(aliasString) != null) {
+            throw new ParseException("Type has already been defined: " + aliasString); //$NON-NLS-1$
+        }
+        scope.registerType(aliasString, targetDeclaration);
         return targetDeclaration;
♻️ Duplicate comments (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (1)

144-148: Fix possible NPE/IllegalStateException when reading fieldClass.TYPE.
fieldClass.get(JsonMetadataStrings.TYPE) can be null, and getAsString() can throw if the element isn’t a primitive/string. This matches the previously reported issue.

                 if (type.isEmpty()) {
-                    if (fieldClass.isJsonObject()) {
-                        type = fieldClass.get(JsonMetadataStrings.TYPE).getAsString();
-                    }
+                    JsonElement typeElement = fieldClass.get(JsonMetadataStrings.TYPE);
+                    if (typeElement != null && typeElement.isJsonPrimitive()) {
+                        type = typeElement.getAsString();
+                    }
                 }
🧹 Nitpick comments (3)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (1)

27-36: Good extension of JSON TSDL coverage; consider tightening validation/error messages for unsupported type values.
The new parser delegations for strings/arrays/struct/floats are a straightforward extension and keep TypeAliasParser as the central dispatcher. One small improvement: when type is present but not a JSON string (or is empty), fail with a targeted ParseException rather than letting downstream code trip over unexpected shapes.

Also applies to: 173-187

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java (2)

29-30: Consider using java.util.Objects.equals() instead of Guava's deprecated method.

The import uses Guava's Objects.equal(), which has been deprecated in favor of the standard library's java.util.Objects.equals(). Consider switching to the JDK method for future maintainability.

Apply this diff to use the standard library method:

-import com.google.common.base.Objects;
+import java.util.Objects;

Then update line 138:

-        if (current != null && (ctf1 || !Objects.equal(decl, current))) {
+        if (current != null && (ctf1 || !Objects.equals(decl, current))) {

97-99: Consider a more descriptive variable name than ctf1.

The boolean ctf1 distinguishes between CTFAntlr (strict duplicate checking) and JSON (lenient duplicate checking) parsing paths. A more descriptive name like isStrictDuplicateCheck, isCTFAntlrPath, or useStrictDuplicateDetection would improve readability.

Example refactor:

-        boolean ctf1 = false;
+        boolean useStrictDuplicateDetection = false;
         if (declaration instanceof CTFAntlrMetadataNode) {
-            ctf1= true;
+            useStrictDuplicateDetection = true;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e76e243 and 6a47048.

📒 Files selected for processing (4)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (4 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java
🧰 Additional context used
🧬 Code graph analysis (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (7)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicarray/DynamicLengthArrayParser.java (1)
  • DynamicLengthArrayParser (33-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicstring/DynamicLengthStringParser.java (1)
  • DynamicLengthStringParser (46-102)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (1)
  • FloatDeclarationParser (66-206)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java (1)
  • IntegerDeclarationParser (81-271)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java (1)
  • StaticLengthArrayParser (33-112)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java (1)
  • StaticLengthStringParser (46-102)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (1)
  • StructParser (95-285)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / build
  • GitHub Check: build / build
  • GitHub Check: build / build
🔇 Additional comments (5)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java (3)

20-20: LGTM!

The import is necessary for the Objects.equals() calls added in registerType and registerIdentifier methods.


175-182: LGTM!

The changes correctly implement duplicate-registration logic:

  • Anonymous types (null/empty names) are skipped appropriately
  • Existing declarations are retrieved by name and compared using Objects.equals
  • Identical declarations can be re-registered (idempotent), while conflicting ones trigger a ParseException

This is a sound defensive approach for handling type registration.


200-201: LGTM! Critical bug fix confirmed.

The changes correctly address the bug flagged in the past review comment:

  • Now uses fIdentifiers.get(name) instead of the incorrect fIdentifiers.get(declaration)
  • The map lookup uses the proper key type (String), making duplicate detection effective
  • Identical declarations can be re-registered, while conflicts are properly caught

The implementation now matches the pattern used in registerType and works as intended.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java (2)

143-145: The simplified null check assumes prior validation.

The condition now only checks fieldName != null, relying on the exception thrown at line 136 to ensure decl is non-null. This is only safe after fixing the ordering issue flagged in lines 133-137. Once that critical issue is resolved, this simplification is appropriate.


138-141: The duplicate field detection logic is intentional but lacks documentation and test coverage.

The code correctly allows CTF2 to idempotently redeclare fields with identical declarations (same name, same type), while CTF1 strictly rejects any duplicate field. This pattern is consistent with DeclarationScope.registerIdentifier() and DeclarationScope.registerVariant(), which both use the same Objects.equals() comparison to allow equal redeclarations.

However, this significant behavioral difference should be documented with:

  1. A comment explaining why CTF2 allows idempotent field redeclarations while CTF1 does not
  2. A test case in CTF2IntegrationTest verifying that duplicate fields with identical declarations are accepted in CTF2 metadata

This will clarify the intent and prevent future confusion about why the check uses Objects.equal(decl, current) instead of always rejecting duplicates.

Comment on lines 133 to +141
scope.registerIdentifier(fieldName, decl);
if (struct.hasField(fieldName)) {
IDeclaration current = struct.getField(fieldName);
if (decl == null) {
throw new ParseException("struct: Cannot add null field " + fieldName); //$NON-NLS-1$
}
Copy link

@coderabbitai coderabbitai bot Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Null checks must occur before calling registerIdentifier and getField.

The current order performs operations with potentially null values before validation:

  1. Line 133 calls scope.registerIdentifier(fieldName, decl) with potentially null fieldName (when both getName() and getRole() return null on lines 127-130) or null decl
  2. Line 134 calls struct.getField(fieldName) with potentially null fieldName
  3. Lines 135-137 check if decl is null, but by then it may already be registered in the scope

This can corrupt the scope state or cause NPEs. Move all null validations before line 133.

Apply this diff to fix the ordering:

         scope.registerIdentifier(fieldName, decl);
-        IDeclaration current = struct.getField(fieldName);
         if (decl == null) {
             throw new ParseException("struct: Cannot add null field " + fieldName); //$NON-NLS-1$
         }
+        if (fieldName == null) {
+            throw new ParseException("struct: field name cannot be null"); //$NON-NLS-1$
+        }
+        IDeclaration current = struct.getField(fieldName);
         if (current != null && (ctf1 || !Objects.equal(decl, current))) {
             throw new ParseException("struct: duplicate field " //$NON-NLS-1$
                     + fieldName);
         }
-
-        if (fieldName != null) {
-            struct.addField(fieldName, decl);
-        }
+        struct.addField(fieldName, decl);

Note: You may also need to move the scope.registerIdentifier call after the null checks, depending on whether registering a null value is acceptable in the scope implementation.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java
around lines 133 to 137, the code calls scope.registerIdentifier(fieldName,
decl) and struct.getField(fieldName) before validating fieldName and decl; move
the null checks for fieldName (result of getName()/getRole()) and decl to before
any use of fieldName or decl, throw the ParseException if decl is null, and only
call scope.registerIdentifier(...) and struct.getField(...) after those
validations succeed (i.e., do not register or query with a null name or
declaration). Ensure registerIdentifier is moved after the null checks so the
scope is not corrupted by null entries.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If fieldName is null the parser will just skip adding the item.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check DeclarationScope.registerIdentifier implementation to see if it handles null fieldName/decl
ast-grep --pattern $'class DeclarationScope {
  $$$
  registerIdentifier($$$) {
    $$$
  }
  $$$
}'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check StructDeclaration.getField implementation to see if it handles null fieldName
ast-grep --pattern $'class StructDeclaration {
  $$$
  getField($$$) {
    $$$
  }
  $$$
}'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Also check if there are any null safety annotations on these methods
rg -n "registerIdentifier.*@Nullable|@NonNull.*registerIdentifier" --type java

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check getField method signatures
rg -n "getField.*@Nullable|@NonNull.*getField" --type java -A2 -B2

Length of output: 6860


🏁 Script executed:

#!/bin/bash
# Find DeclarationScope class file
fd -t f "DeclarationScope.java" --exec cat {}

Length of output: 20583


🏁 Script executed:

#!/bin/bash
# Find StructDeclaration.getField method implementation
rg -n "public.*getField\(" ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java -A10

Length of output: 318


🏁 Script executed:

#!/bin/bash
# Also check if there's a hasField method in StructDeclaration
rg -n "hasField" ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java -B2 -A5

Length of output: 623


@MatthewKhouzam, you're absolutely right that the struct itself won't be corrupted—the guard at line 143 (if (fieldName != null)) ensures addField is only called with a valid field name.

However, there's still a concern at line 133: scope.registerIdentifier(fieldName, decl) is called before any null checks. Looking at the implementation, while this won't throw an NPE (HashMap accepts null keys), it will add a null entry to the scope's identifier registry if fieldName is null, which could pollute the scope state.

Similarly, line 134 calls struct.getField(fieldName) with a potentially null fieldName, though this just returns null safely.

If the intention is to skip processing entirely when fieldName is null (as you've indicated), would it make sense to add an early return or null check before line 133 to avoid these unnecessary operations and keep the scope clean? Something like:

if (fieldName == null) {
    return struct; // or log a warning if appropriate
}
scope.registerIdentifier(fieldName, decl);
// ... rest of the logic

But if having a null entry in the identifier map is acceptable/expected behavior in your design, then the current flow is fine for that use case.


🧬 Code Graph Analysis Results

StructDeclarationParser.java

  • Snippet 1 (excerpt showing conditional addition when fieldName is non-null)
    File: ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java
    Content:

    scope.registerIdentifier(fieldName, decl);
    IDeclaration current = struct.getField(fieldName);
    if (decl == null) {
        throw new ParseException("struct: Cannot add null field " + fieldName); //$NON-NLS-1$
    }
    if (current != null && (ctf1 || !Objects.equal(decl, current))) {
        throw new ParseException("struct: duplicate field " //$NON-NLS-1$
                + fieldName);
    }
    
    if (fieldName != null) {
        struct.addField(fieldName, decl);
    }
    

    Note: This area demonstrates that if fieldName is null, the addField call is skipped, aligning with the user comment about skipping when fieldName is null.

  • Snippet 2 (context where fieldName is assigned for the CTF1 path)
    File: ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java
    Content:

    for (ICTFMetadataNode typeDeclaratorNode : typeDeclaratorList) {
        decl = TypeDeclaratorParser.INSTANCE.parse(typeDeclaratorNode, new TypeDeclaratorParser.Param(trace, typeSpecifierListNode, scope, identifierSB));
    }
    fieldName = identifierSB.toString();
    

    Note: This shows the path where fieldName is derived from the parsed identifier. If this results in null, the subsequent conditional addition would skip adding the field, consistent with the observed behavior described in the user comment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decl should be checked for null before it is registered.
But if it is null, the parser would throw which would then go up until the parser would throw a ctferror. I do not believe it would just ignore that value.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
common/org.eclipse.tracecompass.common.core.tests/META-INF/MANIFEST.MF (1)

24-24: LGTM! Consider adding a version range for the Gson import.

The addition of com.google.gson correctly supports the new JSON metadata parsing functionality introduced in this PR. However, OSGi best practice recommends specifying version ranges for imported packages to ensure compatibility and prevent runtime issues.

Consider applying this diff to add a version range:

- com.google.gson,
+ com.google.gson;version="[2.8.0,3.0.0)",

Adjust the version range to match the actual Gson version used in your project dependencies.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5674972 and 43b5e24.

📒 Files selected for processing (2)
  • common/org.eclipse.tracecompass.common.core.tests/META-INF/MANIFEST.MF (1 hunks)
  • common/org.eclipse.tracecompass.common.core.tests/src/org/eclipse/tracecompass/common/core/tests/log/LoggerTest.java (23 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / build
  • GitHub Check: build / build
  • GitHub Check: build / build
🔇 Additional comments (2)
common/org.eclipse.tracecompass.common.core.tests/src/org/eclipse/tracecompass/common/core/tests/log/LoggerTest.java (2)

129-597: Solid refactoring that improves test maintainability.

The consistent replacement of hardcoded string assertions with structured JSON validation is a good improvement. This approach:

  • Makes tests more resilient to formatting changes
  • Validates the structure of log messages systematically
  • Centralizes the validation logic for easier maintenance

34-35: Verify Gson version compatibility for parseString() usage.

The code at line 108 uses JsonParser.parseString(), which requires Gson 2.8.6 or later. The target platform defines Gson as a dependency, but the exact version cannot be determined from the repository artifacts. Confirm the project uses a compatible Gson version.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BlobDeclaration.java (1)

65-68: Guard condition is always false for non-negative lengths.

The condition fLength > getMaximumSize() at line 66 checks if fLength > fLength * 8, which is always false for non-negative fLength values (and could only be true due to integer overflow if fLength * 8 wraps negative).

If the intent was to remove the previous 1MB limit, consider removing the dead guard entirely. If some limit is still desired, the logic needs correction.

 @Override
 public @NonNull BlobDefinition createDefinition(IDefinitionScope definitionScope, @NonNull String fieldName, @NonNull BitBuffer input) throws CTFException {
-    if (fLength > getMaximumSize()) {
-        throw new CTFException("Length asked: " + fLength + " is larger than the maximum blob size " + getMaximumSize()); //$NON-NLS-1$ //$NON-NLS-2$
-    }
     byte[] array = new byte[fLength];

Also applies to: 90-92

♻️ Duplicate comments (9)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java (1)

65-65: Length validation still missing.

The past review comment correctly identified that the length should be validated before use to ensure it's positive and within reasonable bounds. This validation has not yet been implemented.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (3)

23-28: Fix class Javadoc to describe static-length string.

The Javadoc still says "Dynamic-length string declaration", but this class is StaticLengthStringDeclaration for fixed-length strings. Please update the summary line accordingly while keeping the encoding mention and author.

Suggested change:

-/**
- * Dynamic-length string declaration with encoding support
+/**
+ * Static-length string declaration with encoding support
  *
  * @author Matthew Khouzam
  */

33-44: Align constructor Javadoc with actual parameters.

The Javadoc documents a lengthName parameter that does not exist; the constructor takes int length. This can mislead readers and tools relying on Javadoc.

Suggested change:

     /**
      * Constructor
      *
-     * @param lengthName
-     *            the name of the length field
+     * @param length
+     *            the fixed length of the string in bytes
      * @param encoding
      *            the character encoding
      */

96-99: Correct toString() label to “static_string”.

toString() currently returns "dynamic_string[...]", which contradicts the static-length nature of this declaration.

Suggested change:

     @Override
     public String toString() {
-        return "dynamic_string[" + fLength + "]<" + fEncoding.name() + ">"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        return "static_string[" + fLength + "]<" + fEncoding.name() + ">"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
     }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (1)

211-218: Missing null checks for JSON member properties (previously flagged).

The code at lines 213-215 still lacks null checks before calling getAsString() and getAsJsonObject() on the NAME and FIELD_CLASS elements, risking NullPointerException for malformed input.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/ScopedDefinition.java (1)

165-170: Infinite recursion bug (previously flagged).

Line 169 calls lookupDefinition(lookupPath, defintionToExclude) which is the same method, causing infinite recursion and StackOverflowError. This should delegate to the single-argument version:

-        return lookupDefinition(lookupPath, defintionToExclude);
-    }}
+        return lookupDefinition(lookupPath);
+    }
+}
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDeclaration.java (1)

49-49: Thread safety issue with fFieldArray remains unaddressed.

The past review correctly identified that fFields is a synchronized map, but fFieldArray is accessed and modified without synchronization. This can cause race conditions if multiple threads call addField concurrently.

Additionally, there's a minor formatting issue on line 173.

     public void addField(String fieldTag, IDeclaration declaration) {
+        synchronized (fFields) {
             fFields.put(fieldTag, declaration);
             int size = fFields.size();
             fFieldArray = Arrays.copyOf(fFieldArray, size);
-            fFieldArray[size-1]=declaration;
+            fFieldArray[size - 1] = declaration;
+        }
     }

Also applies to: 169-174

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (1)

152-154: Alignment validation missing in JSON parsing path.

The past review correctly identified that alignment is read directly without validation in the JSON path, while the legacy path (line 184) uses AlignmentParser.INSTANCE.parse() which validates that alignment is positive and a power of 2. This issue remains unaddressed.

Apply this fix to validate alignment consistently:

             if (fieldclass.has(JsonMetadataStrings.ALIGNMENT)) {
-                alignment = fieldclass.get(JsonMetadataStrings.ALIGNMENT).getAsInt();
+                long alignmentValue = fieldclass.get(JsonMetadataStrings.ALIGNMENT).getAsLong();
+                if (alignmentValue <= 0 || (alignmentValue & (alignmentValue - 1)) != 0) {
+                    throw new ParseException("Invalid value for alignment: " + alignmentValue);
+                }
+                alignment = alignmentValue;
             }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/DynamicLengthStringDeclaration.java (1)

32-44: Enforce non‑null contract for lengthName / fLengthName to avoid NPEs

lengthName is annotated @Nullable, but fLengthName is used everywhere as if non‑null (lookup, error message, toString) with no null checks. This creates a mismatch between the declared contract and actual usage and can lead to NPEs if a null ever gets passed.

Since the parser always provides a valid name, it’s safer to enforce non‑null at the API boundary and on the field.

Suggested diff:

@@
-import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
@@
-    private final Charset fEncoding;
-    private final String fLengthName;
+    private final Charset fEncoding;
+    private final @NonNull String fLengthName;
@@
-     * @param lengthName the name of the length field
+     * @param lengthName the name of the length field
@@
-    public DynamicLengthStringDeclaration(@Nullable String lengthName, Charset encoding) {
+    public DynamicLengthStringDeclaration(@NonNull String lengthName, Charset encoding) {
         fLengthName = lengthName;
         fEncoding = encoding;
     }

After this change, please recompile with null‑analysis enabled to confirm there are no annotation conflicts with callers.

🧹 Nitpick comments (11)
common/org.eclipse.tracecompass.common.core.tests/META-INF/MANIFEST.MF (1)

24-24: LGTM. Optional: Consider adding a version range to match project practice.

The Gson import is correct and properly formatted. However, there is precedent in the project for specifying versions on Gson imports: doc/org.eclipse.tracecompass.examples.core/META-INF/MANIFEST.MF uses com.google.gson;version="2.8.2". Since this project does specify versions on other imports (e.g., org.junit;bundle-version="4.0.0"), adding a version constraint would improve consistency.

ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java (1)

121-126: StringDefinition2 handling is consistent; please confirm type hierarchy / ordering

Mapping StringDefinition2 to CTFStringField via getValue() mirrors the existing StringDefinition handling and looks correct.

One thing to double‑check: if StringDefinition2 were ever to extend StringDefinition, the instanceof StringDefinition branch would catch it first and this StringDefinition2 branch would be unreachable. Today this is probably fine (and suggests StringDefinition2 is a separate type), but it may be worth confirming that there is no inheritance relationship, or documenting that assumption here to avoid future surprises if the hierarchy evolves.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java (1)

69-69: Consider adding a comment explaining the empty string parameters.

The element node is constructed with empty strings for type, value, and name parameters. While this appears intentional (since the actual metadata is derived from elementFieldClass), a brief comment explaining why these are empty would improve code clarity.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (1)

64-94: Use an integral max-length literal and double‑check maximum size semantics.

Two small points here:

  1. 1e6 is a double literal; using an integral literal avoids implicit widening/narrowing and better reflects the domain (byte length):
  •    if (rawLength > 1e6) {
    
  •    if (rawLength > 1_000_000L) {
    
    
    
  1. getMaximumSize() returns Integer.MAX_VALUE even though this declaration has a fixed length. Consider whether this should instead reflect fLength (in whatever units getMaximumSize is defined for), or at least be consistent with how other string declarations implement it in this codebase.
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDefinition.java (1)

44-44: Lazy initialization introduces a benign data race.

The fMapping field is now non-final and lazily initialized in getMappings() without synchronization. While this could result in redundant computation under concurrent access, the computation is idempotent (same result each time), so correctness is preserved. If this code is accessed from multiple threads, consider using a local variable pattern to avoid potential visibility issues:

public String getMappings() {
    String mapping = fMapping;
    if (mapping == null) {
        mapping = getDeclaration().getMappingForValue(fValue);
        fMapping = mapping;
    }
    return mapping;
}

Also applies to: 110-113

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDefinition.java (1)

166-192: Consider reducing code duplication between lookup methods.

The two lookupDefinition overloads share nearly identical logic. The first method could delegate to the second to reduce duplication:

     @Override
     public IDefinition lookupDefinition(String lookupPath) {
-        if (lookupPath == null) {
-            return null;
-        }
-        if (lookupPath.equals(fFieldName)) {
-            return fDefinition;
-        }
-        if (lookupPath.equals(fTagDef.getDeclaration().getRole())) {
-            return fTagDef;
-        }
-        if (lookupPath.equals(fDefinition.getDeclaration().getRole())) {
-            return fDefinition;
-        }
-        if (fDefinition instanceof ScopedDefinition) {
-            IDefinition def = ((ScopedDefinition) fDefinition).lookupDefinition(lookupPath, this);
-            if (def != null) {
-                return def;
-            }
-        }
-        final IDefinitionScope definitionScope = getDefinitionScope();
-        if (definitionScope instanceof StructDefinition) {
-            StructDefinition structDefinition = (StructDefinition) definitionScope;
-            return structDefinition.lookupDefinition(lookupPath, this);
-        }
-        return definitionScope.lookupDefinition(lookupPath);
+        return lookupDefinition(lookupPath, this);
     }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java (1)

187-187: Typo in parameter name: "defintionToExclude"

The parameter is misspelled as defintionToExclude (missing 'i' in "definition"). While this doesn't affect functionality, it impacts code readability and should be corrected throughout the file for consistency.

Apply this diff to fix the typo:

-    public Definition lookupDefinition(String lookupPath, ScopedDefinition defintionToExclude) {
-        if (this.equals(defintionToExclude) || lookupPath == null) {
+    public Definition lookupDefinition(String lookupPath, ScopedDefinition definitionToExclude) {
+        if (this.equals(definitionToExclude) || lookupPath == null) {
             return null;
         }
         /*
          * The fields are created in order of appearance, so if a variant or
          * sequence refers to a field that is after it, the field's definition
          * will not be there yet in the hashmap.
          */
         int val = fFieldNames.indexOf(lookupPath);
         if (val != -1) {
             return fDefinitions[val];
         }
         String lookupUnderscored = "_" + lookupPath; //$NON-NLS-1$
         val = fFieldNames.indexOf(lookupUnderscored);
         if (val != -1) {
             return fDefinitions[val];
         }
         for (IDefinition child : fDefinitions) {
             if (child instanceof ScopedDefinition) {
-                if (!child.equals(defintionToExclude)) {
+                if (!child.equals(definitionToExclude)) {
                     if (lookupPath.equals(child.getDeclaration().getRole())) {
                         if (child instanceof Definition) {
                             return (Definition) child;
                         }
                     }
-                    IDefinition def = ((ScopedDefinition) child).lookupDefinition(lookupPath, defintionToExclude);
+                    IDefinition def = ((ScopedDefinition) child).lookupDefinition(lookupPath, definitionToExclude);
                     if (def instanceof Definition) {
                         return (Definition) def;
                     }
                 }
             }
         }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java (1)

422-430: Fix Javadoc for getRole method

The @return documentation states "the role" but the method actually returns the IDeclaration associated with that role.

Apply this diff to correct the Javadoc:

     /**
      * Get the child with a role
      * @param role the role
-     * @return the role
+     * @return the declaration with the specified role, or null if not found
      * @since 5.1
      */
     public @Nullable IDeclaration getRole(String role) {
         return fRoles.get(role);
     }
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java (1)

66-81: Consider adding more specific assertions

The test only verifies that the result is non-null. Consider adding assertions to validate specific properties of the parsed string declaration (e.g., length, encoding) to make the test more robust.

ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java (2)

38-54: Past constructor issues are resolved

The previous review comments flagged constructor signature mismatches, but the current code correctly uses the 5-parameter JsonStructureFieldMemberMetadataNode constructor. The test logic and assertions are correct for IEEE 754 single-precision floats.

Optionally, you could simplify the JsonObject construction by using addProperty instead of wrapping primitives:

         JsonObject fieldClass = new JsonObject();
-        fieldClass.add("length", new JsonPrimitive(32));
-        fieldClass.add("byte-order", new JsonPrimitive("le"));
+        fieldClass.addProperty("length", 32);
+        fieldClass.addProperty("byte-order", "le");

62-80: LGTM: Correct 64-bit float test with proper constructor usage

The test correctly validates IEEE 754 double-precision parsing with the proper 5-parameter constructor. Assertions match the expected exponent (11), mantissa (53), byte order, and alignment values.

Same optional simplification applies here:

         JsonObject fieldClass = new JsonObject();
-        fieldClass.add("length", new JsonPrimitive(64));
-        fieldClass.add("byte-order", new JsonPrimitive("be"));
-        fieldClass.add("alignment", new JsonPrimitive(8));
+        fieldClass.addProperty("length", 64);
+        fieldClass.addProperty("byte-order", "be");
+        fieldClass.addProperty("alignment", 8);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 43b5e24 and 36c3178.

📒 Files selected for processing (35)
  • common/org.eclipse.tracecompass.common.core.tests/META-INF/MANIFEST.MF (1 hunks)
  • common/org.eclipse.tracecompass.common.core.tests/src/org/eclipse/tracecompass/common/core/tests/log/LoggerTest.java (23 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/META-INF/MANIFEST.MF (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/META-INF/MANIFEST.MF (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BlobDeclaration.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java (9 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDefinition.java (2 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/ScopedDefinition.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition2.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java (5 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java (4 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDeclaration.java (4 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDefinition.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java (4 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonTraceMetadataNode.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (4 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicarray/DynamicLengthArrayParser.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicstring/DynamicLengthStringParser.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (2 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java (4 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (2 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/DynamicLengthStringDeclaration.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (5 hunks)
  • ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (13)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicstring/DynamicLengthStringParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicarray/DynamicLengthArrayParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition2.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java
  • common/org.eclipse.tracecompass.common.core.tests/src/org/eclipse/tracecompass/common/core/tests/log/LoggerTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java
🧰 Additional context used
🧬 Code graph analysis (6)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (4)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMemberMetadataNode.java (1)
  • JsonStructureFieldMemberMetadataNode (31-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMetadataNode.java (1)
  • JsonStructureFieldMetadataNode (29-89)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/AlignmentParser.java (1)
  • AlignmentParser (51-117)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-257)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java (3)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (2)
  • NonNullByDefault (66-83)
  • TypeAliasParser (55-222)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/ArrayDeclaration.java (1)
  • ArrayDeclaration (43-194)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-257)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java (2)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMemberMetadataNode.java (1)
  • JsonStructureFieldMemberMetadataNode (31-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (1)
  • FloatDeclarationParser (66-206)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java (2)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMemberMetadataNode.java (1)
  • JsonStructureFieldMemberMetadataNode (31-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (1)
  • TypeAliasParser (55-222)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (3)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/io/BitBuffer.java (1)
  • BitBuffer (32-743)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/Declaration.java (1)
  • Declaration (30-90)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition2.java (1)
  • StringDefinition2 (22-72)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (5)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/CTFJsonMetadataNode.java (1)
  • CTFJsonMetadataNode (33-171)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMemberMetadataNode.java (1)
  • JsonStructureFieldMemberMetadataNode (31-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/AlignmentParser.java (1)
  • AlignmentParser (51-117)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/UnaryIntegerParser.java (1)
  • UnaryIntegerParser (28-68)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-257)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / build
  • GitHub Check: build / build
  • GitHub Check: build / build
🔇 Additional comments (19)
ctf/org.eclipse.tracecompass.ctf.core.tests/META-INF/MANIFEST.MF (1)

27-27: LGTM! Gson import aligns with JSON-based test additions.

The addition of com.google.gson to the Import-Package section is consistent with the broader JSON/TSdl parsing changes and new test classes mentioned in the AI summary (e.g., JsonTraceMetadataNodeTest). The lack of version constraint matches the pattern used in the core bundle and other imports in this manifest.

ctf/org.eclipse.tracecompass.ctf.core/META-INF/MANIFEST.MF (1)

5-5: LGTM! Minor version bump is appropriate for CTF 2 support.

The version bump from 5.0.2 to 5.1.0 correctly reflects the addition of new functionality (LTTng 2.14.3 CTF 2 trace support) while maintaining backward compatibility. This aligns with OSGi semantic versioning conventions for feature additions without breaking API changes.

ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java (1)

41-43: Import of StringDefinition2 is correct and used

The new import cleanly integrates with the existing type imports and is used below in parseField, so there’s no unused‑import or packaging concern here.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java (2)

635-660: LGTM on the mapping lookup fix.

The backward iteration now correctly checks all candidates without early termination, ensuring intervals like [0,100] are not missed when searching for values like 75. The logic is correct.

Note: This approach is O(n) in the worst case when all intervals could potentially contain the value. For large mapping sets, consider an augmented interval tree, but this is likely acceptable for typical CTF use cases.


372-387: Consider thread safety for setMappings.

The setMappings method modifies fMappings and fIntervalTree non-atomically. If this method is called after construction while getMappingForValue is being invoked from another thread, it could result in inconsistent reads.

If setMappings is guaranteed to be called only during construction (before the declaration is shared), this is fine. Otherwise, consider making the interval tree reference volatile or using copy-on-write semantics.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonTraceMetadataNode.java (1)

19-19: LGTM! Consistent library migration from org.json to Gson.

The type change from JSONObject to JsonObject aligns with the Gson-based deserialization used throughout this class (via @SerializedName annotations).

Also applies to: 33-33, 65-65

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDeclaration.java (1)

127-158: Two-branch tag resolution logic is well-implemented.

The implementation correctly handles:

  • IntegerDefinition with mappings or numeric index-based lookup
  • EnumDefinition with the preserved existing string-based lookup
  • Proper bounds checking at lines 136-138 prevents ArrayIndexOutOfBoundsException
  • Clear error messages for undefined tags and unknown selectors
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDefinition.java (2)

39-39: LGTM! Good API versioning and backward compatibility.

The type widening from EnumDefinition to SimpleDatatypeDefinition allows handling both integer-based and enum-based tag definitions. The new constructor is properly annotated with @since 5.1, and the existing EnumDefinition constructor is preserved for backward compatibility.

Also applies to: 45-69, 89-96


138-164: Role-based lookup logic is well-structured.

The extended lookupDefinition method properly:

  • Resolves fields by role using getDeclaration().getRole()
  • Delegates to nested ScopedDefinition with exclusion to prevent infinite loops
  • Falls back through the scope hierarchy appropriately
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java (1)

264-269: LGTM! Bug fix for mapped integer declaration creation.

The fix correctly uses (int) size as the first parameter for the mapped declaration path, aligning it with the non-mapped path on line 268. Previously using base as the size would have created incorrectly-sized integer declarations.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (2)

133-145: LGTM! IEEE 754 size mapping is correct.

The implementation correctly maps:

  • 32-bit → exponent=8, mantissa=24 (IEEE 754 binary32/float)
  • 64-bit → exponent=11, mantissa=53 (IEEE 754 binary64/double)

The error handling for unsupported sizes provides a clear message.


155-192: Legacy parsing path correctly preserved.

The existing TSDL parsing logic is cleanly moved to the else branch, preserving all attribute parsing including proper alignment validation via AlignmentParser.INSTANCE.parse().

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java (3)

208-212: LGTM: Role-based lookup optimization

The role-based short-circuit correctly checks if the lookupPath matches a child's declared role and returns it directly, avoiding unnecessary deep traversal.


223-225: LGTM: Cycle prevention in scope delegation

The addition of the exclusion parameter when delegating to the parent scope correctly prevents infinite recursion by passing this as the definition to exclude.


239-266: LGTM: Recursive role lookup with proper null safety

The enhanced lookupRole method correctly adds null-safety and introduces recursive traversal through nested structures (StructDefinition and VariantDefinition). The recursive helper properly handles the variant's current field selection.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java (3)

59-60: LGTM: Role-to-declaration mapping

The addition of fRoles map provides efficient O(1) lookup for declarations by role. The field is appropriately marked as final and non-null.


348-352: LGTM: Self-registration for role-based navigation

The override correctly propagates the role to the superclass and registers the struct itself in fRoles, enabling parent structures to locate this struct by its role.


216-219: Add duplicate role detection to prevent silent overwrites

When adding fields with roles, the code silently overwrites any existing declaration with the same role. Unlike field names (which trigger a warning if duplicated), roles have no such check. Add validation to detect and handle duplicate roles consistently.

ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java (1)

38-58: The type string "fixed-length-floating-point-number" in the test is correct and matches JsonMetadataStrings.FIXED_LENGTH_FLOATING_POINT exactly. No changes needed.

Likely an incorrect or invalid review comment.

Comment on lines +89 to +111
public void testDynamicLengthStringParsing() throws Exception {
// Test that the parser doesn't throw an exception for dynamic length strings
// The actual parsing logic may not be fully implemented yet
CTFTrace trace = new CTFTrace();
DeclarationScope scope = new DeclarationScope(null, "test");

JsonObject fieldClass = new JsonObject();
fieldClass.add("type", new JsonPrimitive("dynamic-length-string"));
fieldClass.add("encoding", new JsonPrimitive("utf-8"));

JsonStructureFieldMemberMetadataNode node = new JsonStructureFieldMemberMetadataNode(null, "dynamic-length-string", "test", "dyn_string_field", fieldClass);

try {
IDeclaration result = TypeAliasParser.INSTANCE.parse(node,
new TypeAliasParser.Param(trace, scope));
// If we get here without exception, the basic parsing works
assertNotNull(result);
} catch (Exception e) {
// For now, just verify the parser recognizes the type
assertTrue("Parser should handle dynamic-length-string type",
e.getMessage() == null || !e.getMessage().contains("Invalid field class"));
}
}
Copy link

@coderabbitai coderabbitai bot Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Clarify implementation status of dynamic-length string parsing

The comment and try-catch structure suggest the parsing logic "may not be fully implemented yet." If this feature is incomplete, consider:

  1. Marking the test with @Ignore and a TODO comment with a tracking issue
  2. Or document the expected behavior more clearly in the test
  3. Or implement the missing functionality before merging

Tests that allow both success and certain failures make it difficult to detect regressions.

Do you want me to search the codebase to verify if DynamicLengthStringParser is fully implemented?

🤖 Prompt for AI Agents
In
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java
around lines 89-111, the test for dynamic-length-string currently swallows
failures in a try/catch which makes regressions undetectable; first check
whether DynamicLengthStringParser is implemented—if it is not, annotate the test
with @Ignore and add a one-line TODO with a tracking issue/PR number explaining
why it’s ignored; if the parser is implemented, remove the lenient try/catch,
assert the parsed result (assertNotNull) and/or assert specific expected
behavior, and fail the test on any exception so the test reliably detects
regressions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the assert in the catch clause, the test should throw in certain cases? If the parser fails, the test should also fail no?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rate Limit Exceeded

@arfio have exceeded the limit for the number of chat messages per hour. Please wait 2 minutes and 23 seconds before sending another message.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (26)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java (2)

301-316: Previously flagged issues in expandAliases remain unaddressed.

Per past review:

  1. ConcurrentModificationException risk (line 302): Iterating obj.keySet() while calling obj.add() can fail depending on Gson's implementation. Iterate over a copy: new ArrayList<>(obj.keySet()).
  2. String aliases in arrays not expanded (lines 309-312): Only JsonObject elements are recursed into; string alias references directly in arrays won't be resolved.

259-266: JsonParser.parseString can throw JsonSyntaxException outside the try-catch block.

If jsonBlocks[i] contains malformed JSON, JsonParser.parseString() at line 259 throws JsonSyntaxException, but the try-catch at lines 269-273 only covers gson.fromJson(). This could cause an unhandled exception and abort trace parsing.

         for (int i = 1; i < jsonBlocks.length; i++) {
-            JsonElement element = JsonParser.parseString(jsonBlocks[i]);
+            JsonElement element;
+            try {
+                element = JsonParser.parseString(jsonBlocks[i]);
+            } catch (JsonSyntaxException e) {
+                throw new CTFException("Trace cannot be parsed as CTF2", e); //$NON-NLS-1$
+            }
             if (element.isJsonObject()) {

Add null checks before accessing NAME and FIELD_CLASS properties (lines 263-265).

This was flagged in a previous review. Malformed FIELD_ALIAS fragments missing these properties will throw on getAsString() or getAsJsonObject().

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition2.java (1)

24-24: Potential null pointer exception if value is null.

The value parameter in both constructors lacks @NonNull annotation, and fString is stored directly. If a null value is passed, size() and toString() will throw NPE.

Also applies to: 34-37, 48-51

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (1)

152-154: Alignment value not validated in JSON parsing path.

The JSON path reads alignment directly without validation, while the legacy path (line 184) uses AlignmentParser.INSTANCE.parse() which validates that alignment must be positive and a power of 2. Invalid alignment values from JSON metadata could bypass validation.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicstring/DynamicLengthStringParser.java (1)

65-74: Missing null-safety for chained JSON access.

This issue was previously flagged. Line 70 chains multiple calls without null checks. If lengthFieldLocation is not a JSON object or doesn't contain PATH, this will throw an unchecked exception rather than a descriptive ParseException.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (4)

23-27: Fix incorrect class javadoc.

The javadoc says "Dynamic-length string declaration" but this class is StaticLengthStringDeclaration for static-length strings.


33-44: Fix constructor javadoc parameter mismatch.

The javadoc refers to parameter lengthName of type String, but the actual parameter is length of type int.


96-99: Correct toString() to indicate static-length string.

The toString() method returns "dynamic_string" but this class represents a static-length string.


101-105: Implement isBinaryEquivalent instead of returning a TODO stub.

Leaving isBinaryEquivalent as a stub that always returns false breaks semantic equivalence for identical static-length string declarations.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (5)

184-187: Incorrect Javadoc for DYNAMIC_LENGTH_STRING constant.

The Javadoc says "Type string for a null terminated string field class" but this constant represents "dynamic-length-string".


203-206: Incorrect Javadoc for PATH constant.

The Javadoc says "Type string for a structure field class" but this constant represents "path".


220-222: UTF-32 charset handling should account for JDK version compatibility.

Charset.forName("UTF-32BE") and Charset.forName("UTF-32LE") will throw UnsupportedCharsetException at class loading time on JDKs prior to version 22.


249-251: Missing Javadoc for public constants.

MEMBER_CLASSES and MINIMUM_ALIGNMENT are missing Javadoc comments.


253-255: Missing Javadoc and externalized string markers.

ALIGNMENT and BYTE_ORDER constants are missing Javadoc comments and //$NON-NLS-1$ markers.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java (2)

269-271: Add defensive checks for JSON parsing to prevent unhelpful exceptions.

Line 270 assumes SELECTOR_FIELD_LOCATION contains a JSON object with a PATH field that is an array. The has() check only verifies the key exists, not the structure.


365-374: Error message is misleading after adding IntegerDeclaration support.

The code now accepts both EnumDeclaration and IntegerDeclaration as valid tag types, but the error message at line 373 still says "Variant tag must be an enum".

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java (1)

165-167: JsonElement.toString() includes JSON quotes for string values.

Using entry.getValue().toString() on a JsonElement produces the JSON representation, which includes quotes around strings. For example, a JSON string "hello" will become "\"hello\"" as a Java String.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (1)

211-217: Missing null checks for JSON member properties.

memberElement.getAsJsonObject().get(JsonMetadataStrings.NAME) and get(JsonMetadataStrings.FIELD_CLASS) can return null, causing NullPointerException when getAsString() or getAsJsonObject() is called.

ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java (2)

31-51: Reflection-based injection of fEnvironment is brittle

This test directly sets JsonTraceMetadataNode.fEnvironment via reflection. That’s fragile against refactors (field rename/visibility changes) and may eventually break under stricter module access. Prefer going through the actual Gson deserialization path or a package-private/testing seam (e.g., constructor or setter) to inject the environment.

If reflection must stay, centralize it in a helper so failures are easier to diagnose.


53-70: testUidAndPacketHeader only asserts UID, not packet header

Despite the name, this test only sets and asserts the UID; no packet-header setup or assertion is performed. Either rename the test to reflect what it actually covers, or extend it to initialize a minimal fPacketHeader and verify that initialize() wires it correctly (e.g., getPacketHeader() non-null and/or child linkage).

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (1)

144-187: Add null/type checks when inferring type from fieldClass

Here:

if (type.isEmpty()) {
    if (fieldClass.isJsonObject()) {
        type = fieldClass.get(JsonMetadataStrings.TYPE).getAsString();
    }
}

fieldClass.get(JsonMetadataStrings.TYPE) can return null or a non‑primitive value, leading to a NullPointerException or IllegalStateException on getAsString(). This was already flagged in an earlier review.

Consider guarding the access:

-                if (type.isEmpty()) {
-                    if (fieldClass.isJsonObject()) {
-                        type = fieldClass.get(JsonMetadataStrings.TYPE).getAsString();
-                    }
-                }
+                if (type.isEmpty()) {
+                    JsonElement typeElement = fieldClass.get(JsonMetadataStrings.TYPE);
+                    if (typeElement != null && typeElement.isJsonPrimitive()) {
+                        type = typeElement.getAsString();
+                    }
+                }

The added branches for dynamic/static strings and arrays, structs, and floating point types, as well as the alias redefinition check, otherwise look consistent with the existing parser design.

Also applies to: 213-215

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/ScopedDefinition.java (1)

155-170: Fix infinite recursion in lookupDefinition(String, ScopedDefinition)

The two-argument overload currently calls itself with identical parameters, causing infinite recursion and a StackOverflowError at runtime.

Replace the self-call with a delegation to the single-argument overload so the base behavior is preserved and subclasses can override the exclusion-aware form:

-    public @Nullable IDefinition lookupDefinition(@Nullable String lookupPath, @Nullable ScopedDefinition defintionToExclude) {
-        if(defintionToExclude == this) {
-            return null;
-        }
-        return lookupDefinition(lookupPath, defintionToExclude);
-    }}
+    public @Nullable IDefinition lookupDefinition(@Nullable String lookupPath, @Nullable ScopedDefinition defintionToExclude) {
+        if (defintionToExclude == this) {
+            return null;
+        }
+        return lookupDefinition(lookupPath);
+    }
+}
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java (1)

43-73: Harden JSON handling for field-class and validate array length

Two robustness issues here (both previously raised):

  1. Potential NPE/ClassCastException on getFieldClass().getAsJsonObject()
JsonStructureFieldMemberMetadataNode member = (JsonStructureFieldMemberMetadataNode) node;
JsonObject fieldClass = member.getFieldClass().getAsJsonObject();

If getFieldClass() is null or not a JSON object, this will fail at runtime. Consider:

-        JsonStructureFieldMemberMetadataNode member = (JsonStructureFieldMemberMetadataNode) node;
-        JsonObject fieldClass = member.getFieldClass().getAsJsonObject();
+        JsonStructureFieldMemberMetadataNode member = (JsonStructureFieldMemberMetadataNode) node;
+        JsonElement fieldClassElement = member.getFieldClass();
+        if (fieldClassElement == null || !fieldClassElement.isJsonObject()) {
+            throw new ParseException("Static-length array requires a valid field-class object"); //$NON-NLS-1$
+        }
+        JsonObject fieldClass = fieldClassElement.getAsJsonObject();
  1. No validation of lengthField.getAsInt()

lengthField is only checked for presence; negative or unreasonably large values are accepted:

int length = lengthField.getAsInt();

At minimum, enforce non-negative (and optionally a sane upper bound) to avoid malformed metadata causing pathological allocations:

-        int length = lengthField.getAsInt();
+        int length = lengthField.getAsInt();
+        if (length < 0) {
+            throw new ParseException("Static-length array length must be non-negative, got: " + length); //$NON-NLS-1$
+        }

(If you have an agreed maximum length, you can also enforce it here.)

The rest of the parsing logic (element field class resolution via TypeAliasParser and construction of ArrayDeclaration) looks good.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java (3)

29-45: Javadoc still describes dynamic-length instead of static-length.

This documentation issue was already flagged in a previous review but remains unaddressed.


57-68: Error messages still reference "Dynamic-length" instead of "Static-length".

The error messages at lines 59 and 67 incorrectly reference dynamic-length strings and wrong property names. This was previously flagged but not yet fixed.


77-79: Param Javadoc still references wrong parser type.

This documentation issue was previously flagged but remains unaddressed.

🧹 Nitpick comments (7)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java (1)

24-26: Optional: Simplify JSON construction using addProperty.

The current code uses add with JsonPrimitive wrappers, which works correctly. However, JsonObject.addProperty is more idiomatic and eliminates the need for explicit JsonPrimitive instantiation.

Apply this diff to simplify:

-import com.google.gson.JsonPrimitive;
 
         JsonObject fieldClass = new JsonObject();
-        fieldClass.add("length", new JsonPrimitive(32));
-        fieldClass.add("byte-order", new JsonPrimitive("le"));
+        fieldClass.addProperty("length", 32);
+        fieldClass.addProperty("byte-order", "le");
 
@@
         JsonObject fieldClass = new JsonObject();
-        fieldClass.add("length", new JsonPrimitive(64));
-        fieldClass.add("byte-order", new JsonPrimitive("be"));
-        fieldClass.add("alignment", new JsonPrimitive(8));
+        fieldClass.addProperty("length", 64);
+        fieldClass.addProperty("byte-order", "be");
+        fieldClass.addProperty("alignment", 8);

Also applies to: 42-43, 66-68

ctf/org.eclipse.tracecompass.tmf.ctf.ui.swtbot.tests/src/org/eclipse/tracecompass/tmf/ctf/ui/swtbot/tests/TestInvalidCtfTrace.java (1)

205-211: Consider making the label search loop more robust

The loop assumes the relevant text will always be found within the first few labels and may attempt to read beyond the “3 labels” mentioned in the comment if the message is ever missing or the dialog layout changes. A more defensive pattern (e.g., iterating up to dialogBot.labels().size() or breaking once i reaches the last index) would make the test less brittle to UI changes, while still validating the same behavior.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java (1)

286-288: Prefer checking the parsed JsonObject instead of raw string contains.

The string check jsonBlocks[i].contains("id:") is fragile—it could match "id:" appearing in string values or other contexts. Since the JSON is already parsed at line 261, consider checking the parsed object instead.

             } else if (type.equals(JsonMetadataStrings.FRAGMENT_DATA_STREAM)) {
                 fragment = Objects.requireNonNull(gson.fromJson(element, JsonDataStreamMetadataNode.class));
-                if (!jsonBlocks[i].contains("id:")) { //$NON-NLS-1$
+                JsonObject dsObj = element.getAsJsonObject();
+                if (!dsObj.has("id")) { //$NON-NLS-1$
                     ((JsonDataStreamMetadataNode) fragment).setId(-1);
                 }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition2.java (1)

34-52: Consider consolidating constructors or enforcing type safety.

Both constructors perform identical logic, differing only in the declaration parameter type. The second constructor accepts any Declaration, weakening type safety compared to the first which requires StringDeclaration.

If the intent is to support both StringDeclaration and DynamicLengthStringDeclaration, consider using a common base type or interface that both implement, rather than accepting the generic Declaration base class.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicstring/DynamicLengthStringParser.java (1)

77-101: Unused fTrace field in Param class.

The Param class stores a CTFTrace reference that is never used by the parse() method. Either this is dead code or the implementation is incomplete.

Consider either removing the unused field or documenting why it's reserved for future use:

     @NonNullByDefault
     public static final class Param implements ICommonTreeParserParameter {
-        private final CTFTrace fTrace;
-
         /**
          * Parameter constructor
-         *
-         * @param trace the trace
          */
-        public Param(CTFTrace trace) {
-            fTrace = trace;
+        public Param() {
+            // No parameters needed currently
         }
-
-        /**
-         * Get the trace
-         *
-         * @return the trace
-         */
-        public CTFTrace getTrace() {
-            return fTrace;
-        }
     }

Alternatively, if the trace is needed for future enhancements, add a comment explaining the intent.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (1)

64-73: Redundant length validation and inconsistent type usage.

Since fLength is already an int, the negative check on line 67 is only meaningful if the constructor receives a negative int. The assignment to long rawLength on line 66 is unnecessary indirection. Additionally, using 1e6 (a double) for comparison is unusual.

     @Override
     public StringDefinition2 createDefinition(@Nullable IDefinitionScope definitionScope, String fieldName, BitBuffer input) throws CTFException {
-        long rawLength = fLength;
-        if (rawLength < 0) {
-            throw new CTFException("Cannot have a length < 0, declared = " + rawLength); //$NON-NLS-1$
+        if (fLength < 0) {
+            throw new CTFException("Cannot have a length < 0, declared = " + fLength); //$NON-NLS-1$
         }
-        if (rawLength > 1e6) {
-            throw new CTFException("Cannot have a length > 1000000, declared = " + rawLength); //$NON-NLS-1$
+        if (fLength > 1_000_000) {
+            throw new CTFException("Cannot have a length > 1000000, declared = " + fLength); //$NON-NLS-1$
         }
-        int length = (int) rawLength;
-        byte[] bytes = new byte[length];
-        for (int i = 0; i < length; i++) {
+        byte[] bytes = new byte[fLength];
+        for (int i = 0; i < fLength; i++) {
             bytes[i] = (byte) input.get(Byte.SIZE, false);
         }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java (1)

55-61: Role map wiring is reasonable; consider clarifying key semantics

Storing roles in fRoles from both addField (per-field roles) and setRole (struct’s own role) provides the necessary backing for role-based lookups. Behavior is “last write wins” if a struct and one of its fields share the same role string.

If that overlap is either impossible by design or significant when it happens, it may be worth documenting the intended semantics (struct vs. field precedence) or asserting on duplicate role keys. Otherwise the current implementation is fine.

Also applies to: 202-221, 348-352, 422-430

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 36c3178 and c2cdf0c.

📒 Files selected for processing (36)
  • common/org.eclipse.tracecompass.common.core.tests/META-INF/MANIFEST.MF (1 hunks)
  • common/org.eclipse.tracecompass.common.core.tests/src/org/eclipse/tracecompass/common/core/tests/log/LoggerTest.java (23 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/META-INF/MANIFEST.MF (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/META-INF/MANIFEST.MF (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BlobDeclaration.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java (9 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDefinition.java (2 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/ScopedDefinition.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition2.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java (5 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java (4 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDeclaration.java (4 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDefinition.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java (4 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonTraceMetadataNode.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (4 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicarray/DynamicLengthArrayParser.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicstring/DynamicLengthStringParser.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (2 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java (4 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (2 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java (3 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/DynamicLengthStringDeclaration.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (1 hunks)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (5 hunks)
  • ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java (2 hunks)
  • ctf/org.eclipse.tracecompass.tmf.ctf.ui.swtbot.tests/src/org/eclipse/tracecompass/tmf/ctf/ui/swtbot/tests/TestInvalidCtfTrace.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (12)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDeclaration.java
  • ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/META-INF/MANIFEST.MF
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/DynamicLengthStringDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicarray/DynamicLengthArrayParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDefinition.java
  • common/org.eclipse.tracecompass.common.core.tests/src/org/eclipse/tracecompass/common/core/tests/log/LoggerTest.java
🧰 Additional context used
🧬 Code graph analysis (8)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java (2)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMemberMetadataNode.java (1)
  • JsonStructureFieldMemberMetadataNode (31-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (1)
  • FloatDeclarationParser (66-206)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (4)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMemberMetadataNode.java (1)
  • JsonStructureFieldMemberMetadataNode (31-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMetadataNode.java (1)
  • JsonStructureFieldMetadataNode (29-89)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/AlignmentParser.java (1)
  • AlignmentParser (51-117)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-257)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (7)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicarray/DynamicLengthArrayParser.java (1)
  • DynamicLengthArrayParser (33-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicstring/DynamicLengthStringParser.java (1)
  • DynamicLengthStringParser (46-102)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/enumeration/EnumParser.java (1)
  • EnumParser (97-266)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java (1)
  • StaticLengthArrayParser (33-112)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java (1)
  • StaticLengthStringParser (46-102)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (1)
  • StructParser (95-285)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-257)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-257)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicstring/DynamicLengthStringParser.java (3)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (1)
  • NonNullByDefault (66-83)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/DynamicLengthStringDeclaration.java (1)
  • DynamicLengthStringDeclaration (30-116)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-257)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonTraceMetadataNode.java (1)
  • JsonTraceMetadataNode (28-87)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-257)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java (2)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (2)
  • NonNullByDefault (66-83)
  • TypeAliasParser (55-222)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-257)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / build
  • GitHub Check: build / build
  • GitHub Check: build / build
🔇 Additional comments (17)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java (2)

45-53: Constructor fix confirmed—test correctly validates 32-bit float parsing.

The constructor now correctly passes all 5 required parameters (parent, type, value, name, fieldClass), resolving the critical compilation error flagged in previous reviews. The assertions properly verify that FloatDeclarationParser interprets length: 32 as 8-bit exponent and 24-bit mantissa with little-endian byte order.


70-79: Constructor fix confirmed—test correctly validates 64-bit float parsing.

The constructor now correctly passes all 5 required parameters, resolving the critical issue from previous reviews. The assertions properly verify that FloatDeclarationParser interprets length: 64 as 11-bit exponent and 53-bit mantissa with big-endian byte order, plus the specified 8-byte alignment.

ctf/org.eclipse.tracecompass.tmf.ctf.ui.swtbot.tests/src/org/eclipse/tracecompass/tmf/ctf/ui/swtbot/tests/TestInvalidCtfTrace.java (1)

89-89: Updated expected error string for struct-duplicate-field-name looks correct

Aligning the expected message with the new core duplicate-field wording ("struct: duplicate field xxx") keeps this SWTBot test in sync with the parser’s behavior, and the assertContains usage still gives a bit of flexibility. No further changes needed here.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java (1)

270-291: Element-based parsing after alias expansion is correctly implemented.

The switch from jsonBlocks[i] to the pre-parsed and alias-expanded element ensures that alias references are resolved before deserialization. The pattern is consistently applied across all fragment types.

common/org.eclipse.tracecompass.common.core.tests/META-INF/MANIFEST.MF (1)

24-24: LGTM!

The Gson import is correctly added to support the new JSON metadata handling in tests.

ctf/org.eclipse.tracecompass.ctf.core/META-INF/MANIFEST.MF (1)

5-5: LGTM!

The minor version bump to 5.1.0 appropriately reflects the new CTF 2 support features being added.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (1)

155-192: Legacy parsing path correctly preserved.

The existing non-JSON metadata parsing logic is properly maintained within the else block, preserving backward compatibility with traditional TSDL metadata.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java (1)

25-26: Good addition of IntegerDeclaration support for variant tags.

The import and subsequent handling allow integer-based tags in addition to enum-based tags, which aligns with CTF 2 specification support.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java (1)

159-171: Good integration of JSON-based environment extraction.

The logic correctly checks for JsonTraceMetadataNode, extracts the environment, and propagates it to the trace. The null check on line 162 is appropriate.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (1)

192-222: Good addition of JSON-based struct parsing paths.

The new branches correctly handle JsonStructureFieldMetadataNode and JsonStructureFieldMemberMetadataNode with appropriate type checks (isJsonObject(), isJsonArray()). The minimum alignment extraction and member class iteration logic is well-structured.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonTraceMetadataNode.java (1)

19-67: JsonObject migration for environment looks consistent

Switching fEnvironment and getEnvironment() to JsonObject matches the Gson-based metadata model and keeps behavior unchanged apart from the type. No issues from this change alone.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java (1)

264-269: Mapped integer creation now uses size consistently

Using (int) size as the first parameter for createDeclaration in the mappings path aligns it with the unmapped path and the updated IntegerDeclaration factory signature. This fixes the previous base/size mismatch.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDefinition.java (1)

36-69: Variant tag widening and lookup integration look sound

Widening fTagDef to SimpleDatatypeDefinition with a new constructor while retaining the EnumDefinition constructor keeps existing callers working and allows more generic tag types. The updated lookupDefinition methods correctly:

  • Match on the variant’s field name.
  • Expose the tag and current field via their declaration roles.
  • Delegate into the current field when it is a ScopedDefinition, using the exclusion-aware overload.
  • Fall back to the enclosing StructDefinition (or generic scope) while excluding this variant to avoid lookup loops.

This is consistent with the new role-based lookup model.

Also applies to: 139-192

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java (4)

134-143: LGTM: IntervalNode structure is clean and appropriate.

The inner class provides a clear representation of interval boundaries with associated mapping names.


378-387: LGTM: Interval tree construction is correct.

The buildIntervalTree implementation properly flattens all mapping ranges into sorted IntervalNodes.


549-549: LGTM: Using Long.SIZE is more explicit than a SIZE_64 constant.

This improves code clarity by directly referencing the platform's long size.


567-567: LGTM: equals/hashCode properly updated for new fields.

The inclusion of fMappings and getRole() in equality and hashing logic maintains consistency with the new mapping functionality.

Also applies to: 594-599

@arfio
Copy link
Contributor

arfio commented Dec 17, 2025

@bhufmann @PatrickTasse Do you need any help for the review?

@bhufmann
Copy link
Contributor

@bhufmann @PatrickTasse Do you need any help for the review?

Yes, if you could do the review that would be great. Then I can focus on some other tasks. @arfio thanks for offering.

Copy link
Contributor

@arfio arfio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This correctly reads a ctf2 example trace! I am sure a lot of people have been waiting for this addition, thank you!

Also it would be great if tests for role and lookup definitions would be added as a lot of complicated have been added there.

Comment on lines +89 to +111
public void testDynamicLengthStringParsing() throws Exception {
// Test that the parser doesn't throw an exception for dynamic length strings
// The actual parsing logic may not be fully implemented yet
CTFTrace trace = new CTFTrace();
DeclarationScope scope = new DeclarationScope(null, "test");

JsonObject fieldClass = new JsonObject();
fieldClass.add("type", new JsonPrimitive("dynamic-length-string"));
fieldClass.add("encoding", new JsonPrimitive("utf-8"));

JsonStructureFieldMemberMetadataNode node = new JsonStructureFieldMemberMetadataNode(null, "dynamic-length-string", "test", "dyn_string_field", fieldClass);

try {
IDeclaration result = TypeAliasParser.INSTANCE.parse(node,
new TypeAliasParser.Param(trace, scope));
// If we get here without exception, the basic parsing works
assertNotNull(result);
} catch (Exception e) {
// For now, just verify the parser recognizes the type
assertTrue("Parser should handle dynamic-length-string type",
e.getMessage() == null || !e.getMessage().contains("Invalid field class"));
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the assert in the catch clause, the test should throw in certain cases? If the parser fails, the test should also fail no?

Change-Id: Ied093d7edf0e7de76e0dc637699711cf0653dc6b
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Fix all issues with AI Agents 🤖
In
@common/org.eclipse.tracecompass.common.core.tests/src/org/eclipse/tracecompass/common/core/tests/log/LoggerTest.java:
- Around line 105-115: The helper method assertLogMessage should be made
defensive: in assertLogMessage(String message, String expectedLevel, String
expectedPhase, String expectedName) first assert that message.split(":", 2)
produced two parts before accessing parts[0]/parts[1] with a clear failure
message, then wrap/parsing of parts[1] with a try/catch or an assertion that
JSON parsing succeeded; after obtaining the JsonObject validate each expected
JsonElement (e.g., "ph","tid","pid","name") is present and non-null before
calling getAsString()/getAsInt(), and replace bare assertTrue checks with
assertions that include descriptive messages (e.g., "tid should be > 0 but was
X") and use an assertion for expectedName only when expectedName != null.

In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDeclaration.java:
- Around line 169-174: The code uses an unordered HashMap (fFields) alongside a
positional array (fFieldArray) in VariantDeclaration.addField, which can make
numeric indexing inconsistent; change fFields to a LinkedHashMap to preserve
insertion order (update the fFields declaration and any initializations), keep
the addField logic that appends to fFieldArray unchanged so array order matches
map insertion order, and ensure any tests or code relying on map ordering still
function; alternatively, if numeric indexing is not supported, remove the
numeric fallback path and document that only named mappings are valid.

In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java:
- Around line 255-266: The FIELD_ALIAS handling in the second-pass loop of
Metadata.java can NPE when NAME or FIELD_CLASS are missing; update the block
that checks JsonMetadataStrings.TYPE == JsonMetadataStrings.FRAGMENT_FIELD_ALIAS
to also verify obj.has(JsonMetadataStrings.NAME) and
obj.has(JsonMetadataStrings.FIELD_CLASS) before calling
getAsString()/getAsJsonObject(), and only then put into the metadata map; keep
the existing expandAliases(obj, metadata) call and the single-pass ordering
unchanged.

In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java:
- Around line 73-74: Validate that elementFieldClass is a JSON object before
calling getAsJsonObject(): in StaticLengthArrayParser, check
elementFieldClass.isJsonObject() and only call
elementFieldClass.getAsJsonObject() when true; otherwise handle the non-object
case by constructing JsonStructureFieldMemberMetadataNode with the original
elementFieldClass (or return/throw a clear parse error) and then call
TypeAliasParser.INSTANCE.parse with that node and new
TypeAliasParser.Param(trace, scope) so primitives (alias strings) do not cause a
getAsJsonObject() exception.

In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/DynamicLengthStringDeclaration.java:
- Around line 84-87: The loop in DynamicLengthStringDeclaration that fills the
byte[] bytes by calling input.get(Byte.SIZE, false) doesn't check BitBuffer
capacity first; before allocating/reading length bytes verify
input.canRead(Byte.SIZE * length) (or input.canRead(length) per BitBuffer API)
and if it cannot read, throw a clear CTFException indicating insufficient bits
for the requested length and include requested length and remaining capacity;
perform this check before the for-loop that uses input.get(...) to avoid
ambiguous exceptions at runtime.
♻️ Duplicate comments (31)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (4)

25-29: Class javadoc still incorrectly says "Dynamic-length".

The past review comment on this javadoc was marked as addressed, but line 26 still describes this as "Dynamic-length string declaration" instead of "Static-length string declaration".

🔎 Apply this fix
 /**
- * Dynamic-length string declaration with encoding support
+ * Static-length string declaration with encoding support
  *
  * @author Matthew Khouzam
  */

98-101: toString() still incorrectly labels this as "dynamic_string".

The past review comment on this method was marked as addressed, but line 100 still returns a string starting with "dynamic_string" instead of "static_string".

🔎 Apply this fix
     @Override
     public String toString() {
-        return "dynamic_string[" + fLength + "]<" + fEncoding.name() + ">"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        return "static_string[" + fLength + "]<" + fEncoding.name() + ">"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
     }

93-96: getMaximumSize() should reflect the actual enforced limit.

As noted in an earlier comment, getMaximumSize() returns Integer.MAX_VALUE but the validation at line 72 enforces a maximum of 1,000,000 bytes. These should be consistent.

🔎 Align maximum size with validation
     @Override
     public int getMaximumSize() {
-        return Integer.MAX_VALUE;
+        return 1_000_000; // matches validation limit at line 72
     }

35-42: Constructor javadoc parameter description is incorrect.

The past review comment on this constructor javadoc was marked as addressed, but lines 38-39 still describe the parameter as "the name of the length field" when it should document the int length parameter as the fixed byte length of the string.

🔎 Apply this fix
     /**
      * Constructor
      *
      * @param length
-     *            the name of the length field
+     *            the fixed length of the string in bytes
      * @param encoding
      *            the character encoding
      */
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition2.java (1)

24-52: Null safety issue remains unaddressed.

The past review correctly identified that fString and the constructor value parameters lack null safety:

  1. Line 24: fString is not marked @NonNull
  2. Lines 35 and 49: constructor value parameters are not marked @NonNull
  3. Lines 37 and 51: no null validation before assignment
  4. Line 65 (size()) and line 70 (toString()) will throw NPE if fString is null
🔎 Add null safety
+import java.util.Objects;
+
-    private final String fString;
+    private final @NonNull String fString;
 
     public StringDefinition2(@NonNull StringDeclaration declaration,
-            IDefinitionScope definitionScope, @NonNull String fieldName, String value) {
+            IDefinitionScope definitionScope, @NonNull String fieldName, @NonNull String value) {
         super(declaration, definitionScope, fieldName);
-        fString = value;
+        fString = Objects.requireNonNull(value, "value cannot be null");
     }
 
     public StringDefinition2(@NonNull Declaration declaration,
-            IDefinitionScope definitionScope, @NonNull String fieldName, String value) {
+            IDefinitionScope definitionScope, @NonNull String fieldName, @NonNull String value) {
         super(declaration, definitionScope, fieldName);
-        fString = value;
+        fString = Objects.requireNonNull(value, "value cannot be null");
     }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java (1)

301-316: ConcurrentModificationException risk remains despite past review.

The past review comment indicated this was "✅ Addressed in commits de42c12 to c2cdf0c", but the current code still has the issues:

  1. Line 302: Iterating over obj.keySet() while line 305 modifies obj via obj.add(key, ...) can cause ConcurrentModificationException depending on Gson's JsonObject implementation.

  2. Lines 309-313: String aliases inside arrays are not expanded—only objects within arrays are recursed into. If CTF 2 allows {"field-class": ["alias-name"]} patterns, they won't be resolved.

🔎 Proposed fix
 private static void expandAliases(JsonObject obj, Map<String, JsonObject> metadata) {
-    for (String key : obj.keySet()) {
+    for (String key : new java.util.ArrayList<>(obj.keySet())) {
         JsonElement value = obj.get(key);
         if (value.isJsonPrimitive() && value.getAsJsonPrimitive().isString() && metadata.containsKey(value.getAsString())) {
             obj.add(key, metadata.get(value.getAsString()));
         } else if (value.isJsonObject()) {
             expandAliases(value.getAsJsonObject(), metadata);
         } else if (value.isJsonArray()) {
-            for (JsonElement elem : value.getAsJsonArray()) {
-                if (elem.isJsonObject()) {
-                    expandAliases(elem.getAsJsonObject(), metadata);
+            com.google.gson.JsonArray arr = value.getAsJsonArray();
+            for (int i = 0; i < arr.size(); i++) {
+                JsonElement elem = arr.get(i);
+                if (elem.isJsonPrimitive() && elem.getAsJsonPrimitive().isString() && metadata.containsKey(elem.getAsString())) {
+                    arr.set(i, metadata.get(elem.getAsString()));
+                } else if (elem.isJsonObject()) {
+                    expandAliases(elem.getAsJsonObject(), metadata);
                 }
             }
         }
     }
 }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/DynamicLengthStringDeclaration.java (4)

41-43: Change @Nullable String lengthName to @NonNull String lengthName and add the import.

The constructor parameter is still annotated @Nullable, but fLengthName is used without null guards at lines 68, 71, and 108, creating a contract violation. Since the call site never passes null, the parameter should be @NonNull.

Add import org.eclipse.jdt.annotation.NonNull; and update the constructor signature.

🔎 Proposed fix

Add the import:

+import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;

Update the constructor:

-    public DynamicLengthStringDeclaration(@Nullable String lengthName, Charset encoding) {
+    public DynamicLengthStringDeclaration(@NonNull String lengthName, Charset encoding) {

64-69: Add alignRead(input) before reading from BitBuffer.

The method declares byte-level alignment via getAlignment() returning Byte.SIZE, but doesn't call alignRead(input) before reading. This breaks parsing when the BitBuffer position is not byte-aligned.

All comparable Declaration types (StringDeclaration, IntegerDeclaration, etc.) call alignRead() before reading.

🔎 Proposed fix
 @Override
 public StringDefinition2 createDefinition(@Nullable IDefinitionScope definitionScope, String fieldName, BitBuffer input) throws CTFException {
+    alignRead(input);
     IDefinition lenDef = null;
     if (definitionScope != null) {
         lenDef = definitionScope.lookupDefinition(fLengthName);

80-81: Replace magic number with constant or getMaximumSize().

The hardcoded 1e6 (1,000,000) limit is duplicated between this validation and the intended maximum size. This should be defined once to maintain consistency.

🔎 Proposed fix using a constant

At the class level:

 public class DynamicLengthStringDeclaration extends Declaration {
 
+    private static final int MAX_STRING_LENGTH = 1_000_000;
     private final Charset fEncoding;
     private final String fLengthName;

In the validation:

-    if (rawLength > 1e6) {
-        throw new CTFException("Cannot have a length > 1000000, declared = " + rawLength); //$NON-NLS-1$
+    if (rawLength > MAX_STRING_LENGTH) {
+        throw new CTFException("Cannot have a length > " + MAX_STRING_LENGTH + ", declared = " + rawLength); //$NON-NLS-1$

In getMaximumSize():

 @Override
 public int getMaximumSize() {
-    return Integer.MAX_VALUE;
+    return MAX_STRING_LENGTH;

Based on learnings, line 103 should return this constant and line 81 should use it for the error message.


111-115: Implement isBinaryEquivalent or remove the TODO comment.

The method currently returns false for all comparisons, which is safe but potentially inefficient. For proper binary equivalence checking, compare whether other is a DynamicLengthStringDeclaration with matching fLengthName and fEncoding.

🔎 Proposed implementation
 @Override
 public boolean isBinaryEquivalent(IDeclaration other) {
-    // TODO Auto-generated method stub
-    return false;
+    if (!(other instanceof DynamicLengthStringDeclaration)) {
+        return false;
+    }
+    DynamicLengthStringDeclaration otherDecl = (DynamicLengthStringDeclaration) other;
+    return fLengthName.equals(otherDecl.fLengthName) && fEncoding.equals(otherDecl.fEncoding);
 }

Would you like me to open an issue to track this implementation?

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BlobDeclaration.java (1)

86-89: Clarify rationale for removing the size limit or reintroduce bounds checking.

The previous implementation had a hard-coded maximum size of 1,000,000 that protected against excessively large allocations from malformed or malicious trace data. With this change, getMaximumSize() now returns fLength * 8 without an upper bound, and the pre-flight guard in createDefinition (line 66) was also removed.

This means new byte[fLength] will attempt to allocate whatever size is specified in the trace metadata without bounds checking, potentially causing OutOfMemoryError on corrupted or adversarial input.

Can you provide the rationale for removing this safeguard? If dynamic sizing is required for CTF 2 traces, consider reintroducing a configurable or reasonable upper bound to prevent resource exhaustion attacks.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (1)

211-217: Verify null safety for JSON member properties.

Lines 213-214 access memberElement.getAsJsonObject().get(JsonMetadataStrings.NAME) and .get(JsonMetadataStrings.FIELD_CLASS) without null checks. If these properties are missing or have unexpected types, getAsString() or getAsJsonObject() will throw an exception.

A past review comment indicated this was addressed in commits de42c12 to c2cdf0c, but the current code still shows direct property access without validation. If the fix was applied in a different commit range or file version, please confirm. Otherwise, add defensive checks as originally suggested.

Run the following script to verify if null checks were added in recent commits:

#!/bin/bash
# Check if defensive null checks exist in the commit history
git log --oneline --all -S "JsonMetadataStrings.NAME" --grep="null" -- "**/StructParser.java" | head -10
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java (1)

672-697: Verify interval tree logic doesn't produce duplicate mapping names.

The interval tree binary search correctly finds the rightmost node with start <= value, then iterates backward to collect overlapping intervals. However, if a single mapping name has multiple ranges that overlap with the queried value, that name will be added to matches multiple times.

Based on learnings, integer field class mappings should not have overlapping ranges for the same name. Consider adding validation when building the interval tree in buildIntervalTree() to detect and reject (or warn about) such cases, ensuring the assumption holds at construction time rather than silently producing duplicate names at lookup time.

🔎 Proposed validation in buildIntervalTree
 private void buildIntervalTree() {
     fIntervalTree.clear();
+    Map<String, List<IntervalNode>> nodesByName = new HashMap<>();
     for (Map.Entry<String, List<IntegerRange>> entry : fMappings.entrySet()) {
         String name = entry.getKey();
         for (IntegerRange range : entry.getValue()) {
             fIntervalTree.add(new IntervalNode(range.getStart(), range.getEnd(), name));
+            nodesByName.computeIfAbsent(name, k -> new ArrayList<>()).add(
+                new IntervalNode(range.getStart(), range.getEnd(), name));
         }
     }
     Collections.sort(fIntervalTree, Comparator.comparingLong(n -> n.start));
+    // Validate no overlapping intervals for the same name
+    for (Map.Entry<String, List<IntervalNode>> entry : nodesByName.entrySet()) {
+        List<IntervalNode> nodes = entry.getValue();
+        Collections.sort(nodes, Comparator.comparingLong(n -> n.start));
+        for (int i = 1; i < nodes.size(); i++) {
+            if (nodes.get(i - 1).end >= nodes.get(i).start) {
+                throw new IllegalStateException("Overlapping ranges for mapping: " + entry.getKey());
+            }
+        }
+    }
 }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java (2)

269-271: Add defensive checks for JSON parsing to prevent unhelpful exceptions.

Line 270 assumes SELECTOR_FIELD_LOCATION contains a JSON object with a PATH field that is an array, but there are no type or null checks. If the structure is malformed, getAsJsonObject() or get(JsonMetadataStrings.PATH) will throw an unhelpful exception. Additionally, line 271 accesses the last element without verifying the array is non-empty.

🔎 Proposed defensive checks
         if (variant instanceof JsonStructureFieldMemberMetadataNode) {
             JsonObject fieldClass = ((JsonStructureFieldMemberMetadataNode) variant).getFieldClass().getAsJsonObject();
             if (fieldClass.has(SELECTOR_FIELD_LOCATION)) {
-                JsonArray location = (fieldClass.get(SELECTOR_FIELD_LOCATION).getAsJsonObject().get(JsonMetadataStrings.PATH)).getAsJsonArray();
-                variantTag = location.get(location.size() - 1).getAsString();
-                hasTag = true;
+                JsonElement selectorElement = fieldClass.get(SELECTOR_FIELD_LOCATION);
+                if (selectorElement != null && selectorElement.isJsonObject()) {
+                    JsonElement pathElement = selectorElement.getAsJsonObject().get(JsonMetadataStrings.PATH);
+                    if (pathElement != null && pathElement.isJsonArray()) {
+                        JsonArray location = pathElement.getAsJsonArray();
+                        if (location.size() > 0) {
+                            variantTag = location.get(location.size() - 1).getAsString();
+                            hasTag = true;
+                        } else {
+                            throw new ParseException("Selector field location path is empty");
+                        }
+                    } else {
+                        throw new ParseException("Invalid selector field location: missing or invalid PATH");
+                    }
+                } else {
+                    throw new ParseException("Invalid selector field location structure");
+                }
             }

365-374: Update error message to reflect both allowed tag types.

The error message at line 373 states "Variant tag must be an enum" but the code now accepts both EnumDeclaration and IntegerDeclaration as valid tag types. This is misleading for users encountering the error.

🔎 Proposed fix
             } else if (decl instanceof IntegerDeclaration) {
                 // do nothing
             } else {
-                throw new ParseException("Variant tag must be an enum: " + variantTag);//$NON-NLS-1$
+                throw new ParseException("Variant tag must be an enum or integer: " + variantTag);//$NON-NLS-1$
             }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java (2)

187-187: Typo in parameter name: defintionToExclude should be definitionToExclude.

The parameter name is missing an 'i'. This affects readability and consistency across the codebase.

Suggested fix
-    public Definition lookupDefinition(String lookupPath, ScopedDefinition defintionToExclude) {
+    public Definition lookupDefinition(String lookupPath, ScopedDefinition definitionToExclude) {

Note: This rename should be applied consistently throughout the method body.


207-212: Consider reordering conditions for efficiency.

The role-matching condition at line 208 could be evaluated before the exclusion check at line 207 to potentially short-circuit earlier when the role matches.

ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java (1)

30-80: Test coverage is incomplete for CTF 2 floating point sizes.

The tests cover 32-bit and 64-bit floating point parsing, but CTF 2 specification also requires support for 16-bit, 128-bit, and extended sizes (K > 128, multiples of 32). Consider adding tests for these additional sizes once the parser supports them.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (2)

136-144: CTF 2 specification requires additional floating point sizes.

The current implementation only supports 32-bit and 64-bit floating point sizes. According to the CTF 2 specification, support is required for 16-bit, 32-bit, 64-bit, 128-bit, and arbitrary K-bit (where K > 128 and is a multiple of 32) field classes.

Suggested expansion for additional sizes
             if (fieldclass.has(JsonMetadataStrings.LENGTH)) {
                 int size = fieldclass.get(JsonMetadataStrings.LENGTH).getAsInt();
                 // Standard IEEE 754 sizes
-                if (size == 32) {
+                if (size == 16) {
+                    exponent = 5;
+                    mantissa = 11;
+                } else if (size == 32) {
                     exponent = 8;
                     mantissa = 24;
                 } else if (size == 64) {
                     exponent = 11;
                     mantissa = 53;
+                } else if (size == 128) {
+                    exponent = 15;
+                    mantissa = 113;
+                } else if (size > 128 && size % 32 == 0) {
+                    exponent = 15;
+                    mantissa = size - 1 - exponent;
                 } else {
                     throw new ParseException("Unsupported floating point size: " + size);
                 }
             }

152-154: Alignment value lacks validation in JSON parsing path.

The JSON path reads alignment directly without validating that it's positive and a power of 2, unlike the legacy path which uses AlignmentParser.INSTANCE.parse(). Invalid alignment values could cause issues downstream.

Suggested fix using inline validation
             if (fieldclass.has(JsonMetadataStrings.ALIGNMENT)) {
-                alignment = fieldclass.get(JsonMetadataStrings.ALIGNMENT).getAsInt();
+                long alignmentValue = fieldclass.get(JsonMetadataStrings.ALIGNMENT).getAsLong();
+                if (alignmentValue <= 0 || (alignmentValue & (alignmentValue - 1)) != 0) {
+                    throw new ParseException("Invalid value for alignment: " + alignmentValue);
+                }
+                alignment = alignmentValue;
             }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (1)

144-148: Potential NullPointerException when accessing type from fieldClass.

Line 146 calls fieldClass.get(JsonMetadataStrings.TYPE).getAsString() without checking if the returned JsonElement is null. This will throw a NullPointerException if the "type" field is missing from the JSON object.

Suggested fix with null safety
             if (fieldClass != null) {
-                if (type.isEmpty()) {
-                    if (fieldClass.isJsonObject()) {
-                        type = fieldClass.get(JsonMetadataStrings.TYPE).getAsString();
-                    }
-                }
+                if (type.isEmpty() && fieldClass.isJsonObject() && fieldClass.has(JsonMetadataStrings.TYPE)) {
+                    JsonElement typeElement = fieldClass.get(JsonMetadataStrings.TYPE);
+                    if (typeElement != null && typeElement.isJsonPrimitive()) {
+                        type = typeElement.getAsString();
+                    }
+                }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java (1)

69-69: Validate array length before use.

The length value is extracted without validating that it's non-negative or within reasonable bounds. Negative or excessively large values could cause runtime issues.

Suggested validation
         int length = lengthField.getAsInt();
+        if (length < 0) {
+            throw new ParseException("Static-length array length must be non-negative, got: " + length);
+        }
         CTFTrace trace = ((Param) param).getTrace();
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java (1)

137-146: Order of operations: registration before validation.

The code registers the identifier at line 137 before validating that decl is non-null (line 139). If decl is null, the exception will be thrown, but a null entry may have already been added to the scope's identifier registry.

Consider reordering to validate before registering:

Suggested reordering
-        scope.registerIdentifier(fieldName, decl);
-        IDeclaration current = struct.getField(fieldName);
         if (decl == null) {
             throw new ParseException("struct: Cannot add null field " + fieldName); //$NON-NLS-1$
         }
+        scope.registerIdentifier(fieldName, decl);
+        IDeclaration current = struct.getField(fieldName);
 
         if (current != null && !Objects.equal(decl, current)) {
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java (4)

29-45: The Javadoc still describes dynamic-length strings instead of static-length strings.

This issue was previously flagged and marked as addressed, but the documentation in the current code still incorrectly describes dynamic-length string behavior. The class name is StaticLengthStringParser, but the Javadoc discusses "dynamic-length string field class," length fields from other locations, and the "length-field-location property"—none of which apply to static-length strings.


57-68: Error messages and null-safety issues require attention.

Multiple issues in this segment:

  1. Line 59: Error message incorrectly states "Dynamic-length string" (should be "Static-length string")
  2. Line 67: Error message incorrectly references "Dynamic-length" and "length-field-location property" (should reference "Static-length" and "length property")
  3. Line 63: member.getFieldClass().getAsJsonObject() lacks null-checking before calling getAsJsonObject()—if getFieldClass() returns null, this will throw NullPointerException
Additional null-safety concern (new)

Consider adding a null check before line 63:

 JsonStructureFieldMemberMetadataNode member = (JsonStructureFieldMemberMetadataNode) node;
+JsonElement fieldClassElement = member.getFieldClass();
+if (fieldClassElement == null || !fieldClassElement.isJsonObject()) {
+    throw new ParseException("Static-length string requires a valid field class");
+}
-JsonObject fieldClass = member.getFieldClass().getAsJsonObject();
+JsonObject fieldClass = fieldClassElement.getAsJsonObject();

77-79: Param class Javadoc references the wrong parser type.

The Javadoc states "Parameters for the dynamic-length string parser" but this is the StaticLengthStringParser.


70-74: Validate length before construction.

Line 70 extracts the length without validation. While StaticLengthStringDeclaration does validate bounds (< 0 or > 1000000), failing late complicates error attribution. Additionally, getAsInt() will throw NumberFormatException or UnsupportedOperationException if the JSON element is not a valid integer—this should be caught and wrapped in a ParseException.

Proposed validation and error handling
-int length = lengthField.getAsInt();
+int length;
+try {
+    length = lengthField.getAsInt();
+} catch (NumberFormatException | UnsupportedOperationException e) {
+    throw new ParseException("Static-length string 'length' must be a valid integer", e);
+}
+if (length < 0 || length > 1_000_000) {
+    throw new ParseException("Static-length string 'length' must be between 0 and 1,000,000, got: " + length);
+}
 Charset encoding = encodingField != null ?
     JsonMetadataStrings.ENCODINGS.getOrDefault(encodingField.getAsString(), StandardCharsets.UTF_8) :
     StandardCharsets.UTF_8;

Based on past review comment by arfio at line 70.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (4)

179-192: Javadoc for DYNAMIC_LENGTH_STRING is still incorrect.

Line 185-186: The Javadoc states "Type string for a null terminated string field class" but this constant represents "dynamic-length-string", not a null-terminated string. This appears to be a copy-paste error from the NULL_TERMINATED_STRING constant above.

The issue was previously flagged and marked as addressed by arfio, but the code still contains the incorrect documentation.


203-206: PATH constant has misleading Javadoc.

The Javadoc describes this as "Type string for a structure field class" but the constant represents "path", which is a field reference key, not a type string.


213-222: UTF-32 charset initialization will fail on JDK versions prior to 22.

Lines 220-222 use Charset.forName("UTF-32BE") and Charset.forName("UTF-32LE") in a static initializer. These charsets were added to StandardCharsets only in JDK 22, so on earlier JDK versions, Charset.forName() will throw UnsupportedCharsetException at class-loading time, causing the entire class to fail to load.

If this project must support JDK versions prior to 22, the ENCODINGS map should be initialized using a static block with Charset.isSupported() checks or exception handling to gracefully exclude unsupported charsets.

If the project targets JDK 22+, replace with StandardCharsets.UTF_32BE and StandardCharsets.UTF_32LE.

#!/bin/bash
# Check the project's minimum JDK version requirement

echo "Checking Maven compiler configuration..."
fd -e xml pom.xml --exec grep -A 5 "maven.compiler" {}

echo -e "\nChecking MANIFEST.MF for Bundle-RequiredExecutionEnvironment..."
fd -e MF MANIFEST.MF --exec grep "Bundle-RequiredExecutionEnvironment" {}

echo -e "\nChecking for any .java-version or similar files..."
fd -t f "^\\.java-version$|^java\\.version$"

249-255: Missing Javadoc and //$NON-NLS-1$ markers on several constants.

Lines 249, 251, 253, and 255 declare public constants but are missing:

  1. Javadoc comments (inconsistent with the rest of the file)
  2. //$NON-NLS-1$ externalization markers on lines 253 and 255

This reduces maintainability and violates the consistent documentation style established throughout the file.

🧹 Nitpick comments (7)
ctf/org.eclipse.tracecompass.ctf.core.tests/META-INF/MANIFEST.MF (1)

27-27: LGTM! Gson import correctly added for CTF 2 trace parsing tests.

The addition of com.google.gson to Import-Package is necessary for the new JSON-based CTF 2 metadata parsing functionality described in the AI summary. The import is properly formatted and maintains alphabetical order.

Consider specifying a version range for better dependency management, e.g., com.google.gson;version="[2.8.0,3.0.0)", though this is optional given the existing inconsistent versioning pattern in this manifest.

Optional: Verify Gson usage in new test classes
#!/bin/bash
# Verify that Gson is actually imported and used in test classes
rg -n --type java -C3 'import.*gson' ctf/org.eclipse.tracecompass.ctf.core.tests/
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (1)

67-86: Validation is appropriate defensive programming.

Responding to the earlier question on line 73: even if length is validated during metadata parsing, this runtime validation is good defensive programming to prevent corrupted data from causing issues.

Optional: Consider bulk byte reading for performance.

The byte-by-byte loop (lines 77-79) could be replaced with a single bulk read for better performance:

🔎 Potential optimization
-        byte[] bytes = new byte[length];
-        for (int i = 0; i < length; i++) {
-            bytes[i] = (byte) input.get(Byte.SIZE, false);
-        }
+        byte[] bytes = new byte[length];
+        input.get(bytes, 0, length);

Note: Only apply this if BitBuffer.get(byte[], int, int) method exists and is semantically equivalent to reading length bytes.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java (1)

67-156: Clarify the purpose of deprecated constants.

Multiple public constants (UINT_32L_DECL, INT_32L_DECL, UINT_64L_DECL, etc.) have been marked as @Deprecated with a note to "use the standard constructor instead."

Based on learnings, there's a question about whether these declarations are still used or kept solely for API compatibility. If they're retained for backward compatibility, this should be documented explicitly in the deprecation notice (e.g., "Deprecated for removal in version X.Y"). If they're no longer needed, consider removing them in a separate cleanup task.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDeclaration.java (1)

127-152: Review variant resolution logic for correctness and clarity.

The two-branch resolution logic is complex. When the tag is an IntegerDefinition, the code attempts to resolve the variant field either by mappings or by using the tag value as a direct index into fFieldArray.

A few observations:

  1. Index-based lookup risk: Lines 136-139 use tagValue as an array index, assuming variant fields are numbered sequentially from 0. This works only if the variant's field order matches the integer range [0, N-1]. Verify that this assumption holds for all CTF 2 traces or add documentation explaining when numeric indexing is valid.

  2. Error handling: The error messages at lines 137, 144, 148-149, and 154 could be more descriptive. Consider including the tag name, tag value (if applicable), and available field names to aid debugging.

  3. Mapping resolution: Line 132 retrieves mappings from the IntegerDefinition, but if mappings is non-null and doesn't match any field name, the code falls through to line 153 and throws "Unknown enum selector". This error message is confusing for integer-based tags.

💡 Suggestions for improvement
  • Add documentation clarifying when numeric indexing is appropriate.
  • Improve error messages to distinguish between integer-based and enum-based resolution failures.
  • Consider adding validation during variant construction to ensure fields match expected integer ranges if numeric indexing is intended.
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (1)

192-221: Consider using pattern matching for cleaner type checks.

Based on learnings, there's a suggestion to use Java pattern matching for the instanceof checks at lines 192 and 201. This would make the code more concise and eliminate redundant casts.

🔎 Example using pattern matching
-        } else if (struct instanceof JsonStructureFieldMetadataNode) {
-            JsonStructureFieldMetadataNode structNode = (JsonStructureFieldMetadataNode) struct;
+        } else if (struct instanceof JsonStructureFieldMetadataNode structNode) {
             if (structNode.getMinimumAlignment() != 0) {
                 structAlign = AlignmentParser.INSTANCE.parse(struct, null);
             }
             if (structNode.getMemberClasses() != null) {
                 hasBody = true;
                 structBody = struct;
             }
-        } else if (struct instanceof JsonStructureFieldMemberMetadataNode) {
-            JsonStructureFieldMemberMetadataNode memberNode = (JsonStructureFieldMemberMetadataNode) struct;
+        } else if (struct instanceof JsonStructureFieldMemberMetadataNode memberNode) {
             // ... rest of the code

Note: This requires Java 16+ with pattern matching for instanceof.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (1)

213-215: Good addition for type redefinition check, but missing space.

The redefinition check correctly prevents duplicate type definitions. However, there's a minor style issue with missing whitespace.

Note: This check is only applied in the non-JSON path. Verify if the JSON path (lines 108-192) should also have a similar redefinition check before scope.registerType() at line 218.

Suggested fix for spacing
-            if (scope.lookupType(aliasString)!= null) {
+            if (scope.lookupType(aliasString) != null) {
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java (1)

41-44: Consider using addProperty for cleaner JSON construction.

Using addProperty is simpler and more readable than add with new JsonPrimitive(...).

Example simplification
         JsonObject fieldClass = new JsonObject();
-        fieldClass.add("length", new JsonPrimitive(32));
-        fieldClass.add("byte-order", new JsonPrimitive("le"));
+        fieldClass.addProperty("length", 32);
+        fieldClass.addProperty("byte-order", "le");
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c2cdf0c and 9dfa5a0.

📒 Files selected for processing (36)
  • common/org.eclipse.tracecompass.common.core.tests/META-INF/MANIFEST.MF
  • common/org.eclipse.tracecompass.common.core.tests/src/org/eclipse/tracecompass/common/core/tests/log/LoggerTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/META-INF/MANIFEST.MF
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java
  • ctf/org.eclipse.tracecompass.ctf.core/META-INF/MANIFEST.MF
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BlobDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/ScopedDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition2.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonTraceMetadataNode.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicarray/DynamicLengthArrayParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicstring/DynamicLengthStringParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/DynamicLengthStringDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java
  • ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java
  • ctf/org.eclipse.tracecompass.tmf.ctf.ui.swtbot.tests/src/org/eclipse/tracecompass/tmf/ctf/ui/swtbot/tests/TestInvalidCtfTrace.java
🚧 Files skipped from review as they are similar to previous changes (15)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java
  • ctf/org.eclipse.tracecompass.ctf.core/META-INF/MANIFEST.MF
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicarray/DynamicLengthArrayParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicstring/DynamicLengthStringParser.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/ScopedDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java
  • ctf/org.eclipse.tracecompass.tmf.ctf.ui.swtbot.tests/src/org/eclipse/tracecompass/tmf/ctf/ui/swtbot/tests/TestInvalidCtfTrace.java
  • ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java
  • common/org.eclipse.tracecompass.common.core.tests/META-INF/MANIFEST.MF
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java
🧰 Additional context used
🧬 Code graph analysis (4)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java (3)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMemberMetadataNode.java (1)
  • JsonStructureFieldMemberMetadataNode (31-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (1)
  • StaticLengthStringDeclaration (30-111)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-257)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java (3)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/CTFTrace.java (1)
  • CTFTrace (81-1043)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMemberMetadataNode.java (1)
  • JsonStructureFieldMemberMetadataNode (31-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (1)
  • FloatDeclarationParser (66-206)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java (3)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (2)
  • NonNullByDefault (66-83)
  • TypeAliasParser (55-222)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/ArrayDeclaration.java (1)
  • ArrayDeclaration (43-194)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-257)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-257)
🔇 Additional comments (18)
common/org.eclipse.tracecompass.common.core.tests/src/org/eclipse/tracecompass/common/core/tests/log/LoggerTest.java (2)

1-1: Clarify whether this file belongs in this PR.

A previous review comment questioned whether this commit should be in this patch. Given that the PR objectives focus on implementing LTTng 2.14.3 CTF 2 trace support, this logging utility test file appears unrelated to CTF parsing functionality. Please confirm whether these logging test changes are intentional or should be moved to a separate PR.


129-131: Good refactoring to JSON-based assertions.

The refactoring from exact string matching to JSON field validation improves test maintainability. By parsing the JSON payload and asserting on semantic fields (level, phase, name) rather than exact formatting, the tests are more resilient to non-breaking formatting changes while still validating the correct behavior.

Also applies to: 149-153, 195-199, 241-247

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (1)

103-110: LGTM - isBinaryEquivalent is properly implemented.

The method correctly checks type compatibility, compares the defining fields (length and encoding), and uses null-safe comparison for the encoding field.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition2.java (1)

54-71: Methods are correctly implemented given non-null fString.

The getValue(), size(), and toString() methods are properly implemented. They will function correctly once the null safety issue in the constructors (flagged above) is addressed.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java (2)

38-38: LGTM!

The new imports are necessary for the metadata map and JSON element-based parsing.

Also applies to: 40-40, 78-80


270-270: LGTM!

Correctly changed to parse from the already-parsed element instead of re-parsing jsonBlocks[i]. This eliminates redundant parsing and ensures alias expansion is applied.

Also applies to: 277-277, 279-279, 281-281, 283-283, 285-285, 290-290

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/DynamicLengthStringDeclaration.java (2)

46-62: LGTM!

The getter methods correctly expose the encoding and length field name.


96-99: LGTM!

The byte-level alignment is correct for string types.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java (1)

254-266: LGTM on the recursive role lookup helper.

The lookupRoleRecursive method correctly traverses nested StructDefinition and VariantDefinition types to find definitions by role. The recursion is bounded by the structure depth.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (1)

155-192: LGTM on the legacy parsing path refactoring.

The legacy TSDL parsing path is correctly preserved in the else branch, maintaining backward compatibility while adding JSON support.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (1)

173-186: LGTM on new type routing.

The new routing for dynamic/static length strings and arrays, structures, and floating point types follows the established patterns and provides appropriate parameters to each parser.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDefinition.java (2)

45-69: LGTM on the new constructor.

The new constructor accepting SimpleDatatypeDefinition for the tag definition provides more flexibility while maintaining consistency with the existing constructor pattern.


166-192: LGTM on the lookup with exclusion overload.

The new lookupDefinition(String, ScopedDefinition) overload correctly handles exclusion to prevent circular lookups. Passing this at line 189 when delegating to StructDefinition is appropriate to break potential cycles.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java (1)

125-128: Duplicate field check added for CTF1 path.

Good addition for early detection of duplicate fields in the CTF1 parsing path. Note that this duplicates the check at line 143, which will also catch duplicates for both paths. The redundancy is harmless but could be consolidated.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java (1)

79-115: LGTM on the Param class and overall structure.

The Param class follows the established pattern used by other parsers in the codebase, with appropriate @NonNullByDefault annotation and accessor methods.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (2)

50-58: LGTM—new constants are well-documented.

The FIELD_CLASS and NAME constants are properly documented and formatted consistently with the rest of the file.


160-167: LGTM—floating point constants are correctly defined.

The FIXED_LENGTH_FLOATING_POINT and VARIABLE_LENGTH_FLOATING_POINT constants follow the established pattern and are properly documented.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonTraceMetadataNode.java (1)

19-19: Library migration to Gson is complete and correct.

The migration from org.json.JSONObject to com.google.gson.JsonObject is properly implemented. All consumers handle the JsonObject API correctly:

  • JsonTraceMetadataNodeTest.java demonstrates correct usage with .getAsString() calls
  • IOStructGen.java properly converts the JsonObject to Map<String, String> using Gson's entrySet() with appropriate type checking
  • Gson is declared in the bundle's MANIFEST.MF under Import-Package

Comment on lines +105 to +115
private static void assertLogMessage(String message, String expectedLevel, String expectedPhase, String expectedName) {
String[] parts = message.split(":", 2);
assertEquals(expectedLevel, parts[0]);
JsonObject json = JsonParser.parseString(parts[1].trim()).getAsJsonObject();
assertEquals(expectedPhase, json.get("ph").getAsString());
assertTrue(json.get("tid").getAsInt() > 0);
assertTrue(json.get("pid").getAsInt() > 0);
if (expectedName != null) {
assertEquals(expectedName, json.get("name").getAsString());
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add defensive checks for clearer test failure diagnostics.

The helper method still lacks the defensive checks that were suggested in a previous review (marked as "Addressed" but not present in current code). Without bounds checking and null validation, malformed log messages will cause unclear exceptions (NPE, ArrayIndexOutOfBoundsException) instead of descriptive assertion failures.

Add the following defensive improvements:

  1. Validate that split produces 2 parts before array access
  2. Check for null before calling .getAsString() or .getAsInt()
  3. Use descriptive assertion messages for assertTrue checks
  4. Add error handling or assertions around JSON parsing
🔎 Proposed defensive improvements
 private static void assertLogMessage(String message, String expectedLevel, String expectedPhase, String expectedName) {
     String[] parts = message.split(":", 2);
+    assertEquals("Message should have level and JSON parts", 2, parts.length);
     assertEquals(expectedLevel, parts[0]);
+    
     JsonObject json = JsonParser.parseString(parts[1].trim()).getAsJsonObject();
+    assertNotNull("JSON should have 'ph' field", json.get("ph"));
     assertEquals(expectedPhase, json.get("ph").getAsString());
-    assertTrue(json.get("tid").getAsInt() > 0);
-    assertTrue(json.get("pid").getAsInt() > 0);
+    
+    assertNotNull("JSON should have 'tid' field", json.get("tid"));
+    assertTrue("tid should be positive", json.get("tid").getAsInt() > 0);
+    
+    assertNotNull("JSON should have 'pid' field", json.get("pid"));
+    assertTrue("pid should be positive", json.get("pid").getAsInt() > 0);
+    
     if (expectedName != null) {
+        assertNotNull("JSON should have 'name' field when expectedName is provided", json.get("name"));
         assertEquals(expectedName, json.get("name").getAsString());
     }
 }
🤖 Prompt for AI Agents
In
@common/org.eclipse.tracecompass.common.core.tests/src/org/eclipse/tracecompass/common/core/tests/log/LoggerTest.java
around lines 105-115, The helper method assertLogMessage should be made
defensive: in assertLogMessage(String message, String expectedLevel, String
expectedPhase, String expectedName) first assert that message.split(":", 2)
produced two parts before accessing parts[0]/parts[1] with a clear failure
message, then wrap/parsing of parts[1] with a try/catch or an assertion that
JSON parsing succeeded; after obtaining the JsonObject validate each expected
JsonElement (e.g., "ph","tid","pid","name") is present and non-null before
calling getAsString()/getAsInt(), and replace bare assertTrue checks with
assertions that include descriptive messages (e.g., "tid should be > 0 but was
X") and use an assertion for expectedName only when expectedName != null.

Comment on lines 255 to 270
Map<String, JsonObject> metadata = new HashMap<>();

// Second pass: expand string references and parse
for (int i = 1; i < jsonBlocks.length; i++) {
JsonElement element = JsonParser.parseString(jsonBlocks[i]);
if (element.isJsonObject()) {
JsonObject obj = element.getAsJsonObject();
expandAliases(obj, metadata);
if (obj.has(JsonMetadataStrings.TYPE) && obj.get(JsonMetadataStrings.TYPE).getAsString().equals(JsonMetadataStrings.FRAGMENT_FIELD_ALIAS)) {
metadata.put(obj.get(JsonMetadataStrings.NAME).getAsString(), obj.get(JsonMetadataStrings.FIELD_CLASS).getAsJsonObject());
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for CTF 2 specification or documentation comments about alias ordering
rg -i -C3 'forward.{0,20}reference|alias.{0,20}order|field.{0,10}alias' --type java

Repository: eclipse-tracecompass/org.eclipse.tracecompass

Length of output: 24734


🏁 Script executed:

#!/bin/bash
# Search for null checks around getAsString and getAsJsonObject calls in the same file
rg -B3 -A3 'getAsString|getAsJsonObject' ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java | head -100

Repository: eclipse-tracecompass/org.eclipse.tracecompass

Length of output: 1470


🏁 Script executed:

#!/bin/bash
# Look for validation methods or null checks related to JSON metadata properties
rg -i 'has\(.*NAME|has\(.*FIELD_CLASS' --type java | head -20

Repository: eclipse-tracecompass/org.eclipse.tracecompass

Length of output: 254


🏁 Script executed:

#!/bin/bash
# Check if there are null checks or validation for metadata entries in the file
fd 'Metadata.java' | xargs cat -n | grep -A5 -B5 'NAME\|FIELD_CLASS' | head -60

Repository: eclipse-tracecompass/org.eclipse.tracecompass

Length of output: 2903


Add null checks for required FIELD_ALIAS properties.

Lines 264-265 access NAME and FIELD_CLASS properties without null checks. If a malformed FIELD_ALIAS fragment is missing these properties, getAsString() or getAsJsonObject() will throw. Add defensive checks:

if (obj.has(JsonMetadataStrings.TYPE) && obj.get(JsonMetadataStrings.TYPE).getAsString().equals(JsonMetadataStrings.FRAGMENT_FIELD_ALIAS)) {
    if (obj.has(JsonMetadataStrings.NAME) && obj.has(JsonMetadataStrings.FIELD_CLASS)) {
        metadata.put(obj.get(JsonMetadataStrings.NAME).getAsString(), obj.get(JsonMetadataStrings.FIELD_CLASS).getAsJsonObject());
    }
}

Note: The single-pass expansion at line 262 is intentional—the CTF 2 specification requires aliases to reference only "previously occurring" aliases (no forward references), as confirmed by error handling in TypeAliasParser.java.

🤖 Prompt for AI Agents
In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/trace/Metadata.java
around lines 255-266, The FIELD_ALIAS handling in the second-pass loop of
Metadata.java can NPE when NAME or FIELD_CLASS are missing; update the block
that checks JsonMetadataStrings.TYPE == JsonMetadataStrings.FRAGMENT_FIELD_ALIAS
to also verify obj.has(JsonMetadataStrings.NAME) and
obj.has(JsonMetadataStrings.FIELD_CLASS) before calling
getAsString()/getAsJsonObject(), and only then put into the metadata map; keep
the existing expandAliases(obj, metadata) call and the single-pass ordering
unchanged.

Comment on lines +73 to +74
JsonStructureFieldMemberMetadataNode elementNode = new JsonStructureFieldMemberMetadataNode(node, "", "", "", elementFieldClass.getAsJsonObject()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
IDeclaration elementDeclaration = TypeAliasParser.INSTANCE.parse(elementNode, new TypeAliasParser.Param(trace, scope));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Validate element-field-class is a JSON object before conversion.

Line 73 calls elementFieldClass.getAsJsonObject() without verifying the element is actually a JSON object. If the element-field-class is a primitive (e.g., an alias string reference), this will throw an exception.

Suggested fix
-        JsonStructureFieldMemberMetadataNode elementNode = new JsonStructureFieldMemberMetadataNode(node, "", "", "", elementFieldClass.getAsJsonObject()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        if (!elementFieldClass.isJsonObject()) {
+            throw new ParseException("Static-length array element-field-class must be a JSON object");
+        }
+        JsonStructureFieldMemberMetadataNode elementNode = new JsonStructureFieldMemberMetadataNode(node, "", "", "", elementFieldClass.getAsJsonObject()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
🤖 Prompt for AI Agents
In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java
around lines 73-74, Validate that elementFieldClass is a JSON object before
calling getAsJsonObject(): in StaticLengthArrayParser, check
elementFieldClass.isJsonObject() and only call
elementFieldClass.getAsJsonObject() when true; otherwise handle the non-object
case by constructing JsonStructureFieldMemberMetadataNode with the original
elementFieldClass (or return/throw a clear parse error) and then call
TypeAliasParser.INSTANCE.parse with that node and new
TypeAliasParser.Param(trace, scope) so primitives (alias strings) do not cause a
getAsJsonObject() exception.

Comment on lines +84 to +89
byte[] bytes = new byte[length];
for (int i = 0; i < length; i++) {
bytes[i] = (byte) input.get(Byte.SIZE, false);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Check BitBuffer capacity before reading bytes.

The code reads length bytes without verifying that the BitBuffer has sufficient remaining data. If the buffer is exhausted, input.get() will throw a CTFException with a less informative message.

🔎 Proposed fix
     int length = (int)rawLength;
+    int requiredBits = length * Byte.SIZE;
+    if (!input.canRead(requiredBits)) {
+        throw new CTFException("Insufficient buffer capacity. Required: " + length + " bytes, available: " + ((input.capacity() - input.position()) / Byte.SIZE) + " bytes");
+    }
     byte[] bytes = new byte[length];
     for (int i = 0; i < length; i++) {

Note: The BitBuffer snippet from relevant_code_snippets confirms the canRead(int length) method exists and checks (fPosition + length) <= fBitCapacity.

🤖 Prompt for AI Agents
In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/DynamicLengthStringDeclaration.java
around lines 84-87, The loop in DynamicLengthStringDeclaration that fills the
byte[] bytes by calling input.get(Byte.SIZE, false) doesn't check BitBuffer
capacity first; before allocating/reading length bytes verify
input.canRead(Byte.SIZE * length) (or input.canRead(length) per BitBuffer API)
and if it cannot read, throw a clear CTFException indicating insufficient bits
for the requested length and include requested length and remaining capacity;
perform this check before the for-loop that uses input.get(...) to avoid
ambiguous exceptions at runtime.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Fix all issues with AI Agents 🤖
In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java:
- Around line 213-215: The JSON path is missing the redefinition guard: before
calling scope.registerType(...) ensure you check if
scope.lookupType(aliasString) != null and throw the same ParseException("Type
has already been defined: " + aliasString) to avoid overwriting aliases; move or
add this check so it runs for both the legacy and JSON branches (i.e., after the
if/else that builds aliasString but before scope.registerType), and also correct
the minor style by adding a space before the != in the existing lookupType
check.
♻️ Duplicate comments (9)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (4)

184-187: Incorrect Javadoc for DYNAMIC_LENGTH_STRING.

This was already flagged in a previous review. The Javadoc says "null terminated string" but should say "dynamic length string".


203-206: Incorrect Javadoc for PATH constant.

This was already flagged in a previous review. The Javadoc says "structure field class" but should describe a path reference.


217-222: UTF-32 charset JDK compatibility concern.

This was already flagged in a previous review. Charset.forName("UTF-32BE") and Charset.forName("UTF-32LE") may throw UnsupportedCharsetException on JDKs prior to version 22.


249-255: Missing Javadoc and NLS markers for final constants.

These issues were already flagged in previous reviews:

  • MEMBER_CLASSES and MINIMUM_ALIGNMENT are missing Javadoc comments
  • ALIGNMENT and BYTE_ORDER are missing both Javadoc comments and //$NON-NLS-1$ markers
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (1)

144-148: Potential NullPointerException when accessing type from fieldClass.

The call to fieldClass.get(JsonMetadataStrings.TYPE).getAsString() on line 146 can throw NPE if the TYPE key is absent. As previously discussed, the null check should be added and the conditions merged.

🔎 Proposed fix
-            if (type.isEmpty()) {
-                if (fieldClass.isJsonObject()) {
-                    type = fieldClass.get(JsonMetadataStrings.TYPE).getAsString();
-                }
-            }
+            if (type.isEmpty() && fieldClass.isJsonObject()) {
+                JsonElement typeElement = fieldClass.get(JsonMetadataStrings.TYPE);
+                if (typeElement != null && typeElement.isJsonPrimitive()) {
+                    type = typeElement.getAsString();
+                }
+            }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (2)

133-145: JSON parsing path is overly restrictive for CTF 2 specification compliance.

As previously noted, the code only supports 32-bit and 64-bit floating point sizes. CTF 2 specification requires support for 16-bit, 32-bit, 64-bit, 128-bit, and arbitrary K-bit (where K > 128 and is a multiple of 32) field classes.


152-154: Alignment value is not validated in JSON parsing path.

As previously noted, the JSON path reads alignment directly without validation, while the legacy path uses AlignmentParser.INSTANCE.parse() which validates that alignment must be positive and a power of 2. Per the earlier discussion, the AlignmentParser should be used here for consistency.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java (1)

137-146: Critical: Null checks must occur before scope.registerIdentifier call.

The current code calls scope.registerIdentifier(fieldName, decl) at line 137 before validating that decl is non-null (checked at lines 139-141). If decl is null, it will be registered in the scope before the ParseException is thrown, potentially corrupting the scope state.

Additionally, in the non-CTF1 path, fieldName can be null if both getName() and getRole() return null (lines 131-134). This would register a null key in the scope's identifier map.

The null validations should occur before any registration or field operations.

🔎 Proposed fix to reorder null checks before registration
+        // Validate fieldName and decl before any operations
+        if (decl == null) {
+            throw new ParseException("struct: Cannot add null field " + fieldName); //$NON-NLS-1$
+        }
+        if (fieldName == null) {
+            // Skip processing for anonymous/unnamed fields
+            return struct;
+        }
+
         scope.registerIdentifier(fieldName, decl);
         IDeclaration current = struct.getField(fieldName);
-        if (decl == null) {
-            throw new ParseException("struct: Cannot add null field " + fieldName); //$NON-NLS-1$
-        }
 
         if (current != null && !Objects.equal(decl, current)) {
             throw new ParseException("struct: duplicate field " //$NON-NLS-1$
                     + fieldName);
         }
 
-        if (fieldName != null) {
-            struct.addField(fieldName, decl);
-        }
+        struct.addField(fieldName, decl);

Note: Based on the past review comments, there's clarification needed on whether null fieldName should be silently skipped (as suggested by returning early) or should throw an exception. The proposed fix assumes skipping is the intended behavior. If null fieldName should be an error, replace the early return with a ParseException.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java (1)

672-697: The duplicate name issue from the previous review remains unresolved.

As noted in the previous review, when a single mapping name has multiple overlapping ranges, that name will be added to matches multiple times, resulting in duplicate names in the output string.

Example:

  • Mapping: "ERROR": [0-10], [5-15]
  • Query: value = 7
  • Result: ["ERROR", "ERROR"]"ERROR ERROR"

The previous review suggested using LinkedHashSet<String> instead of List<String> to preserve insertion order while deduplicating names. Based on the discussion, consider adding validation when building the interval tree to confirm that mappings don't have overlapping ranges for the same name, or implement the deduplication fix.

🔎 Proposed fix using LinkedHashSet
-    List<String> matches = new ArrayList<>();
+    Set<String> matches = new LinkedHashSet<>();
     // Binary search for rightmost node with start <= value
     int left = 0, right = fIntervalTree.size() - 1;
     int lastValid = -1;
     while (left <= right) {
         int mid = (left + right) / 2;
         if (fIntervalTree.get(mid).start <= value) {
             lastValid = mid;
             left = mid + 1;
         } else {
             right = mid - 1;
         }
     }
     // Check all nodes from lastValid backwards for overlaps
     for (int i = lastValid; i >= 0; i--) {
         IntervalNode node = fIntervalTree.get(i);
         if (node.end >= value) {
             matches.add(node.name);
         }
     }
     return matches.isEmpty() ? "" : Objects.requireNonNull(String.join(" ", matches)); //$NON-NLS-1$ //$NON-NLS-2$
🧹 Nitpick comments (6)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (2)

160-168: Minor formatting inconsistency.

There's no blank line between the FIXED_LENGTH_FLOATING_POINT constant and the Javadoc for VARIABLE_LENGTH_FLOATING_POINT, which is inconsistent with the rest of the file.

Suggested fix
     public static final String FIXED_LENGTH_FLOATING_POINT = "fixed-length-floating-point-number"; //$NON-NLS-1$
+
     /**
      * Type string for a variable length floating point field class
      */

189-193: Minor formatting: missing blank line.

There's no blank line between LENGTH_FIELD_LOCATION and the next constant's Javadoc.

Suggested fix
     public static final String LENGTH_FIELD_LOCATION = "length-field-location"; //$NON-NLS-1$
+
     /**
      * Type string for a fixed length unsigned enumeration field class
      */
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java (1)

125-128: Optional: Redundant duplicate check for CTF1 path.

This duplicate check at lines 125-128 ensures that for the CTF1 path, struct.getField(fieldName) will return null at line 138. This makes the subsequent check at line 143 redundant for CTF1, as it will never throw.

While this doesn't cause incorrect behavior, consider whether the early check here is necessary, or if the unified check at line 143 could handle both CTF1 and CTF2 cases. The current structure is safe but results in two checks for CTF1.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java (1)

171-180: Consider adding invariant validation to IntervalNode.

The IntervalNode constructor accepts start, end, and name but doesn't validate that start <= end. While this may be enforced by the calling code in buildIntervalTree(), adding an assertion or precondition check would make the invariant explicit and catch bugs earlier.

🔎 Proposed validation
 IntervalNode(long start, long end, String name) {
+    if (start > end) {
+        throw new IllegalArgumentException("start must be <= end");
+    }
     this.start = start;
     this.end = end;
     this.name = name;
 }
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java (2)

37-74: Expand test coverage to validate mapping lookup behavior.

The test successfully verifies that the parser creates an IntegerDeclaration with the correct structure, but it doesn't test the actual mapping lookup functionality. Consider adding assertions that call getMappingForValue() (if accessible) to verify:

  1. Value 0 maps to "ZERO"
  2. Value 1 maps to "ONE"
  3. Value 2 returns empty string (no mapping)

This would provide more comprehensive integration testing of the interval tree lookup logic.

🔎 Example test expansion
// After line 73, add:
// Test mapping lookups (if getMappingForValue is accessible)
assertEquals("ZERO", result.getMappingForValue(0));
assertEquals("ONE", result.getMappingForValue(1));
assertEquals("", result.getMappingForValue(2));
assertEquals("", result.getMappingForValue(-1));

Note: This assumes getMappingForValue is accessible from the test. If it's package-private, the test may need to be in the same package or use reflection.


40-61: Consider adding test cases for edge cases and the duplicate name issue.

The current test uses simple non-overlapping single-value ranges. To improve test coverage and catch potential issues like the duplicate name bug, consider adding additional test methods for:

  1. Overlapping ranges for the same name (e.g., "ERROR": [[0, 10], [5, 15]] with value 7) - this would catch the duplicate name issue identified in the previous review
  2. Multiple mappings with overlapping ranges (e.g., "LOW": [0, 5], "MEDIUM": [3, 8] with value 4)
  3. Gaps in mappings (values that don't map to any name)
  4. Signed integers with negative ranges

These tests would help ensure the interval tree implementation handles all scenarios correctly.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9dfa5a0 and e622814.

📒 Files selected for processing (16)
  • common/org.eclipse.tracecompass.common.core.tests/META-INF/MANIFEST.MF
  • common/org.eclipse.tracecompass.common.core.tests/src/org/eclipse/tracecompass/common/core/tests/log/LoggerTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/META-INF/MANIFEST.MF
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonTraceMetadataNode.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java
  • ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java
🚧 Files skipped from review as they are similar to previous changes (10)
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java
  • common/org.eclipse.tracecompass.common.core.tests/META-INF/MANIFEST.MF
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonTraceMetadataNode.java
  • ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/META-INF/MANIFEST.MF
  • common/org.eclipse.tracecompass.common.core.tests/src/org/eclipse/tracecompass/common/core/tests/log/LoggerTest.java
🧰 Additional context used
🧬 Code graph analysis (1)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java (1)
  • IntegerDeclarationParser (81-271)
🔇 Additional comments (12)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (5)

16-19: LGTM!

The imports are appropriate for supporting the ENCODINGS map with charset definitions.


50-60: LGTM!

Constants are properly documented and follow the file's conventions.


179-183: LGTM!

The LENGTH constant is properly documented and follows conventions.


208-216: LGTM!

The STRUCTURE and STRUCT constants are properly documented.


224-247: LGTM!

The ENCODING, STATIC_LENGTH_STRING, STATIC_LENGTH_ARRAY, DYNAMIC_LENGTH_ARRAY, and ELEMENT_FIELD_CLASS constants are properly documented and follow conventions.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (1)

173-186: LGTM!

The new type routing to dedicated parsers is well-structured and follows the existing pattern. Each parser receives the appropriate parameter object.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (1)

155-192: LGTM!

The legacy parsing path is correctly preserved in the else block with unchanged logic and error handling.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java (2)

29-29: LGTM: Appropriate import for null-safe equality checking.

The Guava Objects.equal() import is correctly used at line 143 for comparing declarations safely.


97-98: LGTM: Clear branching for CTF 1.x vs CTF 2.x metadata formats.

The instanceof check provides a clean separation between ANTLR-based (CTF1) and JSON-based (CTF2) parsing paths.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java (3)

43-44: Deprecated constants documented for API compatibility.

The comment on lines 43-44 clarifies that these basic declarations are retained for API compatibility reasons, which addresses the previous review concern. This is an appropriate approach for maintaining backward compatibility while guiding users toward the standard constructor.

Also applies to: 67-156


182-183: LGTM: Interval tree construction is correct.

The implementation correctly builds the interval tree:

  • Uses TreeMap for consistent mapping order
  • Clears and rebuilds the tree when mappings change
  • Creates nodes for all ranges across all mapping names
  • Sorts by start position for efficient binary search

The centralized rebuild approach in setMappings() ensures the interval tree stays synchronized with the mappings.

Also applies to: 409-424


604-604: LGTM: equals/hashCode correctly updated to include mappings and role.

The changes properly maintain the equals/hashCode contract by including fMappings and getRole() in both methods. This ensures that IntegerDeclaration instances with different mappings or roles are correctly distinguished when used in hash-based collections.

Also applies to: 631-636

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java (2)

115-116: Add @deprecated Javadoc tag with deprecation reason.

The @Deprecated annotation should be accompanied by a @deprecated Javadoc tag explaining why this constant is deprecated and what to use instead.

🔎 Suggested improvement
 /**
- * Unsigned 5 bit int, used for event headers
+ * Unsigned 27 bit int, used for event headers
+ * @deprecated This declaration is no longer needed. Use a custom declaration instead.
  */
 @Deprecated
 public static final IntegerDeclaration UINT_27L_DECL = new IntegerDeclaration(27, false, 10, ByteOrder.LITTLE_ENDIAN, Encoding.NONE, "", 1); //$NON-NLS-1$

139-151: Consider renaming fIntervalTree for clarity.

The field fIntervalTree is a sorted list of intervals, not an actual interval tree data structure. Consider renaming to fSortedIntervals or fIntervalList to avoid confusion with the interval tree data structure which has different complexity guarantees.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e622814 and 2aeb3d6.

📒 Files selected for processing (3)
  • common/org.eclipse.tracecompass.common.core.tests/META-INF/MANIFEST.MF
  • common/org.eclipse.tracecompass.common.core.tests/src/org/eclipse/tracecompass/common/core/tests/log/LoggerTest.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • common/org.eclipse.tracecompass.common.core.tests/src/org/eclipse/tracecompass/common/core/tests/log/LoggerTest.java
  • common/org.eclipse.tracecompass.common.core.tests/META-INF/MANIFEST.MF
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / build
  • GitHub Check: build / build
  • GitHub Check: build / build
🔇 Additional comments (2)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java (2)

377-392: LGTM!

The setMappings and buildIntervalTree methods correctly populate and sort the interval list for efficient lookup.


476-483: LGTM!

The simplification to always create IntegerDefinition without inline mapping resolution is a cleaner separation of concerns.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java (1)

120-128: Fix loop to process all declarators, not just the last one.

The loop iterates over typeDeclaratorList but reuses the shared decl variable, so only the final declarator's declaration is retained. Earlier declarators are silently discarded.

Compare with VariantDeclarationParser and TypedefParser, which correctly handle multiple declarators by creating a new declaration variable per iteration and processing it immediately within the loop. The loop here should do the same: create fresh identifierSB and decl variables per iteration, validate each declarator, and add it to the struct within the loop.

🤖 Fix all issues with AI agents
In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition.java:
- Line 29: The class Javadoc's @apiNote for StringDefinition is an incomplete
sentence and lacks cross-reference and deprecation metadata; update the Javadoc
for StringDefinition to complete the @apiNote (e.g., "Avoid using this class as
it is too coupled to StringDeclaration; use StringDefinition2 instead."), add a
@see StringDefinition2 tag for discoverability, and if the intention is to
discourage use, add a @deprecated annotation and a short @deprecated Javadoc
explaining the preferred alternative.

In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java:
- Around line 159-161: In FloatDeclarationParser (method parsing structure field
members), replace the ambiguous variable passed to
AlignmentParser.INSTANCE.parse: use the local
JsonStructureFieldMemberMetadataNode variable named "member" instead of
"floatingPoint" when calling AlignmentParser.INSTANCE.parse inside the
instanceof block that checks for JsonStructureFieldMemberMetadataNode; update
the call so alignment = AlignmentParser.INSTANCE.parse(member, null) to make
intent clear and match the aliased variable.

In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java:
- Around line 64-74: The code calls elementFieldClass.getAsJsonObject() without
ensuring elementFieldClass is a JsonObject, which can throw
IllegalStateException when element-field-class is a string alias; before
creating the JsonStructureFieldMemberMetadataNode, verify elementFieldClass is
non-null and isJsonObject (or handle isJsonPrimitive/string alias) and if it's
not an object either resolve the alias form or throw a ParseException; update
the block around elementFieldClass, JsonStructureFieldMemberMetadataNode, and
the subsequent TypeAliasParser.INSTANCE.parse(...) to branch on
elementFieldClass.isJsonObject() and only call getAsJsonObject() for that case
(or convert/resolve the alias to an object form) so parsing never calls
getAsJsonObject() on a non-object.

In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java:
- Around line 57-71: In parse(ICTFMetadataNode node, ICommonTreeParserParameter
param) of StaticLengthStringParser, update the incorrect error message strings
that reference "Dynamic-length string" to "Static-length string" (specifically
the message thrown when node is not a JsonStructureFieldMemberMetadataNode and
the message thrown when lengthField is null) so the exceptions reflect this
class's responsibility.
- Around line 29-44: The class Javadoc for StaticLengthStringParser incorrectly
describes dynamic-length strings; update the comment for
StaticLengthStringParser to describe static-length string fields: explain they
are fixed-size sequences of encoded Unicode codepoints of a specified byte
length, how padding/NULL handling works for static-length strings (e.g.,
trailing bytes beyond the first NUL are padding), and reference that the length
is inherent to the field rather than coming from another length field; keep the
author tag and adjust wording to match the behavior implemented in
StaticLengthStringParser.

In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java:
- Around line 201-226: The code in StructParser.java redundantly checks for null
after isJsonObject() on memberNode.getFieldClass() and lacks null-safety when
accessing memberElement fields; change to call JsonObject outerFieldClass =
memberNode.getFieldClass().getAsJsonObject() (remove the unreachable null check)
and guard accesses: check
outerFieldClass.has(JsonMetadataStrings.MINIMUM_ALIGNMENT) before calling
getAsLong(), and for each memberElement ensure memberElement.isJsonObject() and
that its JsonObject has(JsonMetadataStrings.NAME) and
has(JsonMetadataStrings.FIELD_CLASS) and that those entries are non-null (and
FIELD_CLASS is a JSON object) before calling getAsString()/getAsJsonObject(); on
missing required fields either throw a ParseException with a clear message or
skip that member, and use those safe values to construct
JsonStructureFieldMemberMetadataNode and addChild.

In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java:
- Around line 25-30: The class Javadoc incorrectly says "Dynamic-length string
declaration"; update the documentation for StaticLengthStringDeclaration to
accurately describe it as a static-length string declaration (e.g.,
"Static-length string declaration with encoding support") so the comment matches
the class name StaticLengthStringDeclaration and avoid copy-paste confusion.
- Around line 93-96: The getMaximumSize() implementation in
StaticLengthStringDeclaration incorrectly returns Integer.MAX_VALUE; update
StaticLengthStringDeclaration.getMaximumSize() to return the actual declared
maximum in bits by computing fLength * Byte.SIZE (matching the approach used by
IntegerDeclaration and ArrayDeclaration) so the fixed-length string reports its
true maximum size based on the fLength field.

In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java:
- Around line 259-261: Add Javadoc comments for the ALIGNMENT and BYTE_ORDER
constants (public static final String ALIGNMENT and BYTE_ORDER) matching the
style used for other constants in JsonMetadataStrings.java: include a brief
description of what each constant represents in the JSON metadata (e.g.,
alignment of a type and byte order/endianess), annotate with the //$NON-NLS-1$
suffix as present, and place the Javadoc immediately above each constant
declaration.
🧹 Nitpick comments (7)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (1)

67-85: Simplify: fLength is already int, no need for long conversion.

The rawLength variable and subsequent cast back to int are unnecessary since fLength is already an int. Also consider using an integer literal 1_000_000 instead of 1e6 for clarity.

♻️ Proposed simplification
 @Override
 public StringDefinition2 createDefinition(@Nullable IDefinitionScope definitionScope, String fieldName, BitBuffer input) throws CTFException {
-    long rawLength = fLength;
-    if (rawLength < 0) {
-        throw new CTFException("Cannot have a length < 0, declared = " + rawLength); //$NON-NLS-1$
+    if (fLength < 0) {
+        throw new CTFException("Cannot have a length < 0, declared = " + fLength); //$NON-NLS-1$
     }
-    if (rawLength > 1e6) {
-        throw new CTFException("Cannot have a length > 1000000, declared = " + rawLength); //$NON-NLS-1$
+    if (fLength > 1_000_000) {
+        throw new CTFException("Cannot have a length > 1000000, declared = " + fLength); //$NON-NLS-1$
     }
-    int length = (int) rawLength;
-    byte[] bytes = new byte[length];
-    for (int i = 0; i < length; i++) {
+    byte[] bytes = new byte[fLength];
+    for (int i = 0; i < fLength; i++) {
         bytes[i] = (byte) input.get(Byte.SIZE, false);
     }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java (1)

138-150: Asymmetric duplicate-field handling between CTF1 and CTF2 paths.

  • CTF1 path (lines 125-128): Throws unconditionally if field already exists
  • CTF2 path: Allows re-adding the same declaration silently (line 143 only throws if declarations differ)

If this asymmetry is intentional for CTF2 compatibility, consider adding a brief comment explaining the design rationale.

ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java (2)

58-70: Test name is misleading: only UID is tested, not packet header.

The method testUidAndPacketHeader only verifies getUid(). The packet header field (fPacketHeader) is not set or validated. Consider either:

  1. Renaming to testUidParsing()
  2. Adding packet header verification to complete the test
♻️ Option 1: Rename the test
-    public void testUidAndPacketHeader() throws Exception {
+    public void testUidParsing() throws Exception {

31-51: Consider testing via Gson deserialization instead of reflection.

Directly setting private fields via reflection is fragile—tests will break silently if field names are refactored. Using actual Gson deserialization would better validate the integration:

Gson gson = new Gson();
String json = "{\"environment\":{\"hostname\":\"test-host\"}}";
JsonTraceMetadataNode node = gson.fromJson(json, JsonTraceMetadataNode.class);

If reflection is preferred for isolation, this is acceptable but worth noting the trade-off.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (1)

227-229: Redefinition check added for non-JSON path; consider parity for JSON path.

The new guard prevents duplicate type registration in the non-JSON path. However, the JSON path (lines 143-206) proceeds directly to scope.registerType at line 232 without a similar check. If redefinition should be an error for both paths, consider adding the check before line 232 as well.

Proposed fix for parity
+        if (aliasString != null && scope.lookupType(aliasString) != null) {
+            throw new ParseException("Type has already been defined: " + aliasString); //$NON-NLS-1$
+        }
         scope.registerType(aliasString, targetDeclaration);
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java (1)

80-104: Param class is defined but never used in parse().

The parse() method doesn't validate or use the param argument as a Param instance. The trace is never accessed. Either remove the unused Param class or add validation similar to StaticLengthArrayParser:

♻️ Option 1: Add param validation if trace is needed later
     @Override
     public IDeclaration parse(ICTFMetadataNode node, ICommonTreeParserParameter param) throws ParseException {
         if (!(node instanceof JsonStructureFieldMemberMetadataNode)) {
             throw new ParseException("Static-length string only supported in JSON metadata"); //$NON-NLS-1$
         }
+        if (!(param instanceof Param)) {
+            throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$
+        }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java (1)

672-697: Binary search followed by linear scan has O(n) worst case.

The current algorithm correctly uses binary search to find the starting point, but the backwards scan (lines 690-695) degrades to O(n) when many intervals overlap or start at similar values. For typical CTF mappings with few entries, this is acceptable.

Consider documenting this trade-off or using an interval tree data structure if large mapping sets become common:

+    // Note: For small mapping sets (typical in CTF), linear scan after binary search
+    // is acceptable. For large sets, consider using a proper interval tree.
     String getMappingForValue(long value) {
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3d8a6f and 49eb341.

📒 Files selected for processing (32)
  • common/org.eclipse.tracecompass.common.core.tests/META-INF/MANIFEST.MF
  • common/org.eclipse.tracecompass.common.core.tests/src/org/eclipse/tracecompass/common/core/tests/log/LoggerTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/META-INF/MANIFEST.MF
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BlobDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/ScopedDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonTraceMetadataNode.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/AlignmentParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicarray/DynamicLengthArrayParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java
  • ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java
  • ctf/org.eclipse.tracecompass.tmf.ctf.ui.swtbot.tests/src/org/eclipse/tracecompass/tmf/ctf/ui/swtbot/tests/TestInvalidCtfTrace.java
🚧 Files skipped from review as they are similar to previous changes (11)
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonTraceMetadataNode.java
  • common/org.eclipse.tracecompass.common.core.tests/src/org/eclipse/tracecompass/common/core/tests/log/LoggerTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java
  • ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BlobDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicarray/DynamicLengthArrayParser.java
🧰 Additional context used
🧬 Code graph analysis (3)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (7)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicarray/DynamicLengthArrayParser.java (1)
  • DynamicLengthArrayParser (33-121)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicstring/DynamicLengthStringParser.java (1)
  • DynamicLengthStringParser (46-106)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (1)
  • FloatDeclarationParser (67-213)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java (1)
  • StaticLengthArrayParser (33-116)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (1)
  • StructParser (96-289)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-263)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/variant/VariantParser.java (1)
  • VariantParser (200-400)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java (3)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMemberMetadataNode.java (1)
  • JsonStructureFieldMemberMetadataNode (31-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (1)
  • StaticLengthStringDeclaration (30-111)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-263)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonTraceMetadataNode.java (1)
  • JsonTraceMetadataNode (28-87)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / build
  • GitHub Check: build / build
  • GitHub Check: build / build
🔇 Additional comments (27)
ctf/org.eclipse.tracecompass.ctf.core.tests/META-INF/MANIFEST.MF (1)

27-27: LGTM!

The com.google.gson import is correctly placed alphabetically and follows the existing pattern for Google library imports in this manifest (no version constraints). This aligns with the project-wide move to Gson-based JSON handling for CTF metadata parsing.

common/org.eclipse.tracecompass.common.core.tests/META-INF/MANIFEST.MF (1)

24-24: LGTM!

The com.google.gson import is correctly positioned alphabetically after the other com.google.common.* imports and follows the existing pattern (no version constraints). This addition properly supports the Gson-based JSON metadata handling introduced across the project.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (2)

43-64: LGTM!

Constructor and getters are straightforward. The validation in createDefinition() handles edge cases.


98-110: LGTM!

The toString() provides a clear representation, and isBinaryEquivalent() correctly compares both length and encoding using null-safe comparison.

ctf/org.eclipse.tracecompass.tmf.ctf.ui.swtbot.tests/src/org/eclipse/tracecompass/tmf/ctf/ui/swtbot/tests/TestInvalidCtfTrace.java (1)

89-89: LGTM!

The updated error message expectation correctly aligns with the new ParseException message format in StructDeclarationParser.java (lines 126-127 and 144-145).

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDefinition.java (2)

109-114: LGTM! Lazy initialization is correctly implemented.

The pattern is safe because fValue is immutable and getMappingForValue() is deterministic—concurrent calls will compute the same result. The benign race on fMapping is acceptable here.


62-67: LGTM!

Constructor correctly initializes fMapping to null to enable lazy computation in getMappings().

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/AlignmentParser.java (1)

107-126: LGTM! JSON-based alignment parsing for structure field members.

The validation flow is correct: null-check → JSON object check → alignment key presence → primitive check → value extraction with validation.

One note: if fieldclass exists but has no ALIGNMENT key, the method falls through to throw a generic error at line 128. This appears intentional as alignment is a required attribute, but consider if a default value would be more appropriate in the JSON path (similar to how the legacy path handles defaults).

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java (2)

155-160: LGTM! Proper null and type validation for JSON fieldClass.

The pattern-matched instanceof with subsequent null/type validation is consistent with the validation pattern used across other TSDL parsers in this PR.


267-270: LGTM! Correct parameter fix for createDeclaration with mappings.

The change from using base to (int) size as the first parameter aligns with line 272 (the non-mappings path) and matches the expected method signature where size is the first parameter.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDeclaration.java (3)

128-139: LGTM! Integer-based variant tag lookup via mappings or array index.

The logic correctly handles two cases:

  1. If mappings exist, resolve field by mapping name
  2. Otherwise, use the tag value as an index into fFieldArray

The bounds check at line 135 properly guards against invalid indices.


170-172: Array resizing on every addField call is acceptable for typical use.

Arrays.copyOf creates a new array on each call, resulting in O(n²) total time for n fields. This is acceptable given CTF variants typically have few fields. If performance becomes a concern, consider using an ArrayList internally.


47-48: The thread-safety concern about removing Collections.synchronizedMap is unfounded.

VariantDeclaration.addField() is called only during metadata parsing (a single-threaded phase). Once parsing completes, the declaration instances become effectively immutable—createDefinition() only reads fFields and fFieldArray during event processing and never modifies them. The concurrent event reading phase only accesses declarations for reading, never for writing. Removing synchronization is a valid performance optimization without thread-safety implications.

Likely an incorrect or invalid review comment.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java (2)

186-225: LGTM! Enhanced lookup with exclusion and role-based matching.

The updated lookupDefinition method correctly:

  1. Exits early for self-exclusion to prevent infinite loops
  2. Checks direct field matches first
  3. Falls back to role-based matching on child declarations
  4. Recursively searches through nested ScopedDefinition children
  5. Properly delegates to parent scope while passing exclusion context

252-264: LGTM! Recursive role lookup through nested structures.

The helper method correctly traverses nested StructDefinition and VariantDefinition types to find fields by role. The recursion through variant's current field ensures dynamic variant selections are properly searched.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java (1)

144-203: LGTM! Comprehensive field class type dispatch with clean switch structure.

The switch statement properly handles all CTF2 JSON field class types with appropriate parser delegation. Each case correctly constructs the necessary parser parameters.

Minor note: Line 193 passes null for the identifier parameter to StructParser.Param - verify this is intentional for anonymous/inline struct definitions.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (1)

130-161: LGTM! JSON-based floating point parsing with IEEE 754 size mapping.

The JSON parsing branch correctly:

  1. Validates fieldClass as a JSON object
  2. Maps standard IEEE 754 sizes (32-bit, 64-bit) to exponent/mantissa values
  3. Properly rejects unsupported but valid sizes with a TODO for future work
  4. Parses byte order and alignment from JSON fields
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDefinition.java (3)

45-69: New constructor with SimpleDatatypeDefinition looks good.

The new constructor properly generalizes the tag definition type from EnumDefinition to SimpleDatatypeDefinition, enabling broader CTF2 support. The @since 5.1 annotation is appropriate for the API addition.


139-164: Enhanced lookupDefinition with role-based resolution is well-structured.

The method now supports role-based lookups for CTF2 compatibility. The null-safety is maintained since String.equals(null) returns false. The delegation pattern to nested ScopedDefinition and parent StructDefinition properly handles hierarchical lookups.


166-192: Overloaded lookupDefinition correctly propagates exclusion context.

The method properly passes definitionToExclude to nested scoped definitions while passing this to the parent struct definition, maintaining consistent exclusion semantics to prevent infinite recursion.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java (2)

43-77: Parse method implementation is well-structured.

The method properly validates inputs, extracts required properties, and delegates element type resolution to TypeAliasParser. The error messages are clear and specific.


79-115: Param class is well-defined and properly utilized.

Unlike StaticLengthStringParser.Param, this class is correctly validated and its fields are used in the parse() method.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java (4)

140-143: Deprecation of UINT_27L_DECL is properly documented.

The @Deprecated annotation with guidance to use the factory method is appropriate.


170-179: IntervalNode inner class is appropriately designed.

Simple data holder for interval-based mapping lookups. The package-private visibility is suitable for internal use.


603-637: Updated hashCode and equals correctly include new state.

The inclusion of fMappings and getRole() ensures that declarations with different mappings or roles are correctly distinguished.


507-515: Simplified createDefinition defers mapping resolution.

The method now always creates a base IntegerDefinition, with mapping resolution handled separately. This is a cleaner separation of concerns.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)

220-222: ENCODINGS map is well-defined with common UTF charsets.

The use of Map.of() ensures immutability. The supported encodings cover standard UTF variants.

Comment on lines +64 to +74
JsonElement elementFieldClass = fieldClass.get(JsonMetadataStrings.ELEMENT_FIELD_CLASS);
if (elementFieldClass == null) {
throw new ParseException("Static-length array requires element-field-class property"); //$NON-NLS-1$
}

int length = lengthField.getAsInt();
CTFTrace trace = ((Param) param).getTrace();
DeclarationScope scope = ((Param) param).getScope();

JsonStructureFieldMemberMetadataNode elementNode = new JsonStructureFieldMemberMetadataNode(node, "", "", "", elementFieldClass.getAsJsonObject()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
IDeclaration elementDeclaration = TypeAliasParser.INSTANCE.parse(elementNode, new TypeAliasParser.Param(trace, scope));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Search for element-field-class usage patterns
rg -n "element-field-class|ELEMENT_FIELD_CLASS" --type=java -B2 -A5

Repository: eclipse-tracecompass/org.eclipse.tracecompass

Length of output: 5297


🏁 Script executed:

# Look for similar getAsJsonObject() calls and how they're handled
rg -n "getAsJsonObject\(\)" --type=java -B3 -A2

Repository: eclipse-tracecompass/org.eclipse.tracecompass

Length of output: 36518


🏁 Script executed:

# Check TypeAliasParser to understand what it expects as input
fd "TypeAliasParser.java" --type f

Repository: eclipse-tracecompass/org.eclipse.tracecompass

Length of output: 214


🏁 Script executed:

# Look for JsonStructureFieldMemberMetadataNode usage patterns
rg -n "JsonStructureFieldMemberMetadataNode" --type=java -B2 -A2

Repository: eclipse-tracecompass/org.eclipse.tracecompass

Length of output: 50401


Add type check before calling getAsJsonObject() on elementFieldClass.

The code at line 73 calls elementFieldClass.getAsJsonObject() without verifying it's actually a JsonObject. Since element-field-class can be a string alias reference (like other field-class properties in the codebase), this will throw IllegalStateException for non-object values. Add a null and type check before the call, similar to the validation already done for the outer fieldClass at line 54.

🤖 Prompt for AI Agents
In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java
around lines 64 - 74, The code calls elementFieldClass.getAsJsonObject() without
ensuring elementFieldClass is a JsonObject, which can throw
IllegalStateException when element-field-class is a string alias; before
creating the JsonStructureFieldMemberMetadataNode, verify elementFieldClass is
non-null and isJsonObject (or handle isJsonPrimitive/string alias) and if it's
not an object either resolve the alias form or throw a ParseException; update
the block around elementFieldClass, JsonStructureFieldMemberMetadataNode, and
the subsequent TypeAliasParser.INSTANCE.parse(...) to branch on
elementFieldClass.isJsonObject() and only call getAsJsonObject() for that case
(or convert/resolve the alias to an object form) so parsing never calls
getAsJsonObject() on a non-object.

Comment on lines +29 to +44
/**
* A dynamic-length string field class is an abstract string field class which
* describes dynamic-length string fields.
*
* A dynamic-length string field is a sequence of zero or more contiguous
* encoded Unicode codepoints. All the encoded codepoints of a dynamic-length
* string field before the first "NULL" (U+0000) codepoint, if any, form the
* resulting string value. The first U+0000 codepoint, if any, and all the
* following bytes are considered padding (garbage data).
*
* The length, or number of bytes, of a dynamic-length string field is the
* value of another, anterior (already encoded/decoded) length field. A
* consumer can locate this length field thanks to the length-field-location
* property of the dynamic-length string field class.
*
* @author Matthew Khouzam
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Javadoc describes dynamic-length string but this is StaticLengthStringParser.

The class documentation appears to be copied from DynamicLengthStringParser. It should describe static-length string fields instead.

📝 Suggested documentation fix
 /**
- * A dynamic-length string field class is an abstract string field class which
- * describes dynamic-length string fields.
+ * A static-length string field class describes static-length string fields.
  *
- * A dynamic-length string field is a sequence of zero or more contiguous
+ * A static-length string field is a sequence of zero or more contiguous
  * encoded Unicode codepoints. All the encoded codepoints of a dynamic-length
  * string field before the first "NULL" (U+0000) codepoint, if any, form the
  * resulting string value. The first U+0000 codepoint, if any, and all the
  * following bytes are considered padding (garbage data).
  *
- * The length, or number of bytes, of a dynamic-length string field is the
- * value of another, anterior (already encoded/decoded) length field. A
- * consumer can locate this length field thanks to the length-field-location
- * property of the dynamic-length string field class.
+ * The length, or number of bytes, of a static-length string field is a
+ * fixed value specified in the field class's length property.
  *
  * @author Matthew Khouzam
  */
🤖 Prompt for AI Agents
In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java
around lines 29 - 44, The class Javadoc for StaticLengthStringParser incorrectly
describes dynamic-length strings; update the comment for
StaticLengthStringParser to describe static-length string fields: explain they
are fixed-size sequences of encoded Unicode codepoints of a specified byte
length, how padding/NULL handling works for static-length strings (e.g.,
trailing bytes beyond the first NUL are padding), and reference that the length
is inherent to the field rather than coming from another length field; keep the
author tag and adjust wording to match the behavior implemented in
StaticLengthStringParser.

Comment on lines +57 to +71
public IDeclaration parse(ICTFMetadataNode node, ICommonTreeParserParameter param) throws ParseException {
if (!(node instanceof JsonStructureFieldMemberMetadataNode)) {
throw new ParseException("Dynamic-length string only supported in JSON metadata"); //$NON-NLS-1$
}

JsonStructureFieldMemberMetadataNode member = (JsonStructureFieldMemberMetadataNode) node;
JsonElement fieldClassElement = member.getFieldClass();
if (fieldClassElement == null || !fieldClassElement.isJsonObject()) {
throw new ParseException(getClass().getName() + " fieldclass must be a json object."); //$NON-NLS-1$
}
JsonObject fieldClass = fieldClassElement.getAsJsonObject();
JsonElement lengthField = fieldClass.get(JsonMetadataStrings.LENGTH);
if (lengthField == null) {
throw new ParseException("Dynamic-length string requires length-field-location property"); //$NON-NLS-1$
}
Copy link

@coderabbitai coderabbitai bot Jan 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Error messages reference "Dynamic-length string" instead of "Static-length string".

The error messages appear to be copied from DynamicLengthStringParser and should be updated for consistency.

📝 Suggested fix
         if (!(node instanceof JsonStructureFieldMemberMetadataNode)) {
-            throw new ParseException("Dynamic-length string only supported in JSON metadata"); //$NON-NLS-1$
+            throw new ParseException("Static-length string only supported in JSON metadata"); //$NON-NLS-1$
         }
         ...
         if (lengthField == null) {
-            throw new ParseException("Dynamic-length string requires length-field-location property"); //$NON-NLS-1$
+            throw new ParseException("Static-length string requires length property"); //$NON-NLS-1$
         }
🤖 Prompt for AI Agents
In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java
around lines 57 - 71, In parse(ICTFMetadataNode node, ICommonTreeParserParameter
param) of StaticLengthStringParser, update the incorrect error message strings
that reference "Dynamic-length string" to "Static-length string" (specifically
the message thrown when node is not a JsonStructureFieldMemberMetadataNode and
the message thrown when lengthField is null) so the exceptions reflect this
class's responsibility.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment was already there and duplicating it makes addressing the review harder

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arfio, I apologize for the duplication. You're right that duplicate comments make reviews harder to manage. I'll avoid repeating the same issue if it's already been flagged elsewhere. Thank you for the feedback!

Comment on lines +201 to 226
} else if (struct instanceof JsonStructureFieldMemberMetadataNode memberNode) {
if (memberNode.getFieldClass().isJsonObject()) {
JsonElement fieldClassElement = memberNode.getFieldClass();
if (fieldClassElement == null || !fieldClassElement.isJsonObject()) {
throw new ParseException(getClass().getName() + " fieldclass must be a json object."); //$NON-NLS-1$
}
JsonObject outerFieldClass = fieldClassElement.getAsJsonObject();
JsonElement minimumAlignment = outerFieldClass.get(JsonMetadataStrings.MINIMUM_ALIGNMENT);
if (minimumAlignment != null) {
structAlign = minimumAlignment.getAsLong();
}
JsonElement memberClasses = outerFieldClass.get(JsonMetadataStrings.MEMBER_CLASSES);
if (memberClasses != null && memberClasses.isJsonArray()) {
hasBody = true;
for (JsonElement memberElement : memberClasses.getAsJsonArray()) {
if (memberElement.isJsonObject()) {
String name = memberElement.getAsJsonObject().get(JsonMetadataStrings.NAME).getAsString();
JsonElement fieldClass = memberElement.getAsJsonObject().get(JsonMetadataStrings.FIELD_CLASS);
JsonStructureFieldMemberMetadataNode childNode = new JsonStructureFieldMemberMetadataNode(memberNode, "", "", name, fieldClass.getAsJsonObject()); //$NON-NLS-1$ //$NON-NLS-2$
memberNode.addChild(childNode);
}
}
structBody = memberNode;
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Redundant null check and missing null-safety on JSON element access.

  1. Lines 203-206 are unreachable: line 202 already confirms isJsonObject() is true, so fieldClassElement cannot be null and must be a JSON object.

  2. Lines 217-218 lack null checks: memberElement.getAsJsonObject().get(...) could return null, and subsequent getAsString()/getAsJsonObject() would throw.

Proposed fix
         } else if (struct instanceof JsonStructureFieldMemberMetadataNode memberNode) {
-            if (memberNode.getFieldClass().isJsonObject()) {
-                JsonElement fieldClassElement = memberNode.getFieldClass();
-                if (fieldClassElement == null || !fieldClassElement.isJsonObject()) {
-                    throw new ParseException(getClass().getName() + " fieldclass must be a json object."); //$NON-NLS-1$
-                }
-                JsonObject outerFieldClass = fieldClassElement.getAsJsonObject();
+            JsonElement fieldClassElement = memberNode.getFieldClass();
+            if (fieldClassElement != null && fieldClassElement.isJsonObject()) {
+                JsonObject outerFieldClass = fieldClassElement.getAsJsonObject();
                 JsonElement minimumAlignment = outerFieldClass.get(JsonMetadataStrings.MINIMUM_ALIGNMENT);
                 if (minimumAlignment != null) {
                     structAlign = minimumAlignment.getAsLong();
                 }
                 JsonElement memberClasses = outerFieldClass.get(JsonMetadataStrings.MEMBER_CLASSES);
                 if (memberClasses != null && memberClasses.isJsonArray()) {
                     hasBody = true;
                     for (JsonElement memberElement : memberClasses.getAsJsonArray()) {
                         if (memberElement.isJsonObject()) {
-                            String name = memberElement.getAsJsonObject().get(JsonMetadataStrings.NAME).getAsString();
-                            JsonElement fieldClass = memberElement.getAsJsonObject().get(JsonMetadataStrings.FIELD_CLASS);
-                            JsonStructureFieldMemberMetadataNode childNode = new JsonStructureFieldMemberMetadataNode(memberNode, "", "", name, fieldClass.getAsJsonObject()); //$NON-NLS-1$ //$NON-NLS-2$
+                            JsonObject memberObj = memberElement.getAsJsonObject();
+                            JsonElement nameElement = memberObj.get(JsonMetadataStrings.NAME);
+                            JsonElement fieldClass = memberObj.get(JsonMetadataStrings.FIELD_CLASS);
+                            if (nameElement == null || fieldClass == null || !fieldClass.isJsonObject()) {
+                                continue; // or throw ParseException
+                            }
+                            String name = nameElement.getAsString();
+                            JsonStructureFieldMemberMetadataNode childNode = new JsonStructureFieldMemberMetadataNode(memberNode, "", "", name, fieldClass.getAsJsonObject()); //$NON-NLS-1$ //$NON-NLS-2$
                             memberNode.addChild(childNode);
                         }
                     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} else if (struct instanceof JsonStructureFieldMemberMetadataNode memberNode) {
if (memberNode.getFieldClass().isJsonObject()) {
JsonElement fieldClassElement = memberNode.getFieldClass();
if (fieldClassElement == null || !fieldClassElement.isJsonObject()) {
throw new ParseException(getClass().getName() + " fieldclass must be a json object."); //$NON-NLS-1$
}
JsonObject outerFieldClass = fieldClassElement.getAsJsonObject();
JsonElement minimumAlignment = outerFieldClass.get(JsonMetadataStrings.MINIMUM_ALIGNMENT);
if (minimumAlignment != null) {
structAlign = minimumAlignment.getAsLong();
}
JsonElement memberClasses = outerFieldClass.get(JsonMetadataStrings.MEMBER_CLASSES);
if (memberClasses != null && memberClasses.isJsonArray()) {
hasBody = true;
for (JsonElement memberElement : memberClasses.getAsJsonArray()) {
if (memberElement.isJsonObject()) {
String name = memberElement.getAsJsonObject().get(JsonMetadataStrings.NAME).getAsString();
JsonElement fieldClass = memberElement.getAsJsonObject().get(JsonMetadataStrings.FIELD_CLASS);
JsonStructureFieldMemberMetadataNode childNode = new JsonStructureFieldMemberMetadataNode(memberNode, "", "", name, fieldClass.getAsJsonObject()); //$NON-NLS-1$ //$NON-NLS-2$
memberNode.addChild(childNode);
}
}
structBody = memberNode;
}
}
}
} else if (struct instanceof JsonStructureFieldMemberMetadataNode memberNode) {
JsonElement fieldClassElement = memberNode.getFieldClass();
if (fieldClassElement != null && fieldClassElement.isJsonObject()) {
JsonObject outerFieldClass = fieldClassElement.getAsJsonObject();
JsonElement minimumAlignment = outerFieldClass.get(JsonMetadataStrings.MINIMUM_ALIGNMENT);
if (minimumAlignment != null) {
structAlign = minimumAlignment.getAsLong();
}
JsonElement memberClasses = outerFieldClass.get(JsonMetadataStrings.MEMBER_CLASSES);
if (memberClasses != null && memberClasses.isJsonArray()) {
hasBody = true;
for (JsonElement memberElement : memberClasses.getAsJsonArray()) {
if (memberElement.isJsonObject()) {
JsonObject memberObj = memberElement.getAsJsonObject();
JsonElement nameElement = memberObj.get(JsonMetadataStrings.NAME);
JsonElement fieldClass = memberObj.get(JsonMetadataStrings.FIELD_CLASS);
if (nameElement == null || fieldClass == null || !fieldClass.isJsonObject()) {
continue; // or throw ParseException
}
String name = nameElement.getAsString();
JsonStructureFieldMemberMetadataNode childNode = new JsonStructureFieldMemberMetadataNode(memberNode, "", "", name, fieldClass.getAsJsonObject()); //$NON-NLS-1$ //$NON-NLS-2$
memberNode.addChild(childNode);
}
}
structBody = memberNode;
}
}
}
🤖 Prompt for AI Agents
In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java
around lines 201 - 226, The code in StructParser.java redundantly checks for
null after isJsonObject() on memberNode.getFieldClass() and lacks null-safety
when accessing memberElement fields; change to call JsonObject outerFieldClass =
memberNode.getFieldClass().getAsJsonObject() (remove the unreachable null check)
and guard accesses: check
outerFieldClass.has(JsonMetadataStrings.MINIMUM_ALIGNMENT) before calling
getAsLong(), and for each memberElement ensure memberElement.isJsonObject() and
that its JsonObject has(JsonMetadataStrings.NAME) and
has(JsonMetadataStrings.FIELD_CLASS) and that those entries are non-null (and
FIELD_CLASS is a JSON object) before calling getAsString()/getAsJsonObject(); on
missing required fields either throw a ParseException with a clear message or
skip that member, and use those safe values to construct
JsonStructureFieldMemberMetadataNode and addChild.

Code assisted by CodeRabbit (GPT 5) for javadoc

Change-Id: Iaf2558ab50b1f47604da28f4529bd094135a4ce5
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Change-Id: Ic10d79e4e72a043e9116d554f5dffacd34013fa6
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Change-Id: Ib3654d5468236a9e3ab1a2a2b0cb49dbfc76e251
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Change-Id: I724d84c0b1f5c300ee73c4f2c2b0b9fa3f4ca3d1
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Change-Id: Icb35ac1c931e398be30debfa45c539f8c9fcd245
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Change-Id: I30afb71bbcf7ff688590b95b7f48caf53b9d3ed4
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Change-Id: Ie35533f33a482aff519f9472b0a34b088be1506e
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Change-Id: I8a1408772b8e1ca2e634fa892e7d8a3c05349877
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Needed for expanding aliases

Change-Id: I97039e706002602347cb6d06fbcfecbbd084b55d
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Add variant definition constructor for CTF2

Change-Id: I21f56a284c6fcee147d3714445ed30d81b706c1a
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Change-Id: Ief637e1c6bc49aca4bed87b586224df9383c1a9e
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Remove infinite recurstion if something is not found. (due to roles in ctf2)

Change-Id: Ifa62ed5807a17e307c044e066399cf15fae2bc74
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
O(log(n)) instead of O(n)

This patch was made with the assistance of Claude Sonnet 4.5

Change-Id: Ic46ff28a84e45beb8462f642340db19d04fa40fc
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Found with CodeRabbit.

Change-Id: Ifa4be68a71fc98e6ca4604c290d50d6840746451
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Change-Id: I600c3d760717956097e41cb2db44de0cc58086ce
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Change-Id: I60f3854afcdf4454847ca49bfdee0ca7d89f9601
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
optimizations negatively affect ctf2. Roles do not work with it.

Change-Id: I34812fe76934c62f00ae3de10cdfad074e996f7f
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Change-Id: If58b118283f9a5e3778e832edd94e358c23cded8
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Change-Id: I40faac6cc2590480c061824beb952d6a19cb2f12
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Change-Id: I018e6cfa1f3e7aeed14953de76d6d9f34adf8e64
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
made in part by claude sonnet 4.5. Many bad hallucinations needed to be manually fixed.
Corrected by CodeRabbit (GPT5)

Change-Id: Ibee4b0cf144f2afa922ae968fd17d6065e18b257
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Generated by Claude Sonnet 4.5, manually fixed by me.

Change-Id: Ieec23f0b0f783775a166b530c9c5c75bc0190c53
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Do not accept double typealiases with the same value.

Change-Id: I2affb15f6faf83cd0292a7310febbad8ae657513
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Clean up the hashcode.
Fix a corner case in getMappings

Change-Id: Iec698c9761fde045a0b9945e65ebcda97fa99cb4
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Add verification to AlignmentParser to match CTF2 specs here.
https://diamon.org/ctf/

Change-Id: I86b1ede3f0b74ae9f9dd40087580013c13a092a7
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
With Java 25, flows can go to different TIDs. This allows the tests to pass.

Change-Id: Ic26850e16ce813ba2c70b0af71b9caa6af0805f2
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🤖 Fix all issues with AI agents
In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/ScopedDefinition.java:
- Around line 163-168: The method lookupDefinition(@Nullable String lookupPath,
@Nullable ScopedDefinition definitionToExclude) currently calls itself causing
infinite recursion and has an extra closing brace; change the call to delegate
to the single-parameter overload lookupDefinition(lookupPath) instead of
lookupDefinition(lookupPath, definitionToExclude) and remove the stray extra '}'
so the method returns the result of the single-parameter overload when
definitionToExclude != this.

In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDeclaration.java:
- Around line 168-173: addField currently always appends to fFieldArray after
fFields.put, so overwriting an existing fieldTag makes fFieldArray inconsistent
with fFields and breaks index-based lookups in createDefinition; change addField
to detect whether the key already existed (e.g. check
fFields.containsKey(fieldTag) or capture the previous value from fFields.put)
and if it did, find and replace the existing entry in fFieldArray (or rebuild
fFieldArray from fFields.values()) instead of blindly growing the array; ensure
createDefinition continues to rely on the corrected fFieldArray ordering.
- Around line 128-139: The IntegerDefinition branch in VariantDeclaration (where
def instanceof IntegerDefinition, tagDef, getMappings(), getIntegerValue())
doesn't handle the case where both mappings and tagValue are null, so
fDeclarationToPopulate can remain unset and later produce a misleading "Unknown
enum selector" error; update that branch to explicitly detect mappings==null &&
tagValue==null and throw a CTFException with a clear message (e.g., "Missing
integer tag value or mappings for variant " + toString()) or otherwise set
fDeclarationToPopulate to a sensible default before falling through, ensuring
the exception refers to an integer-based tag and using the existing identifiers
tagDef, fDeclarationToPopulate, getMappings(), and getIntegerValue().
- Around line 47-49: The field fDeclarationToPopulate is used only within
createDefinition and causes a race when multiple threads call createDefinition
on the same VariantDeclaration; make fDeclarationToPopulate a local variable
inside createDefinition (replace uses of fDeclarationToPopulate with a local
IDeclaration declarationToPopulate) and update all assignments and references in
that method accordingly; also review the change from a synchronized map to a
plain HashMap for fFields and, if concurrent access is expected, restore
thread-safety (e.g., use Collections.synchronizedMap, ConcurrentHashMap, or
synchronize access around fFields) to avoid concurrent modification issues.

In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/AlignmentParser.java:
- Around line 107-126: In the JsonStructureFieldMemberMetadataNode branch of
AlignmentParser (the else-if handling JsonStructureFieldMemberMetadataNode), add
a return of the default alignment when the fieldclass does not contain
JsonMetadataStrings.ALIGNMENT instead of falling through to the ParseException;
specifically: if fieldclass.has(JsonMetadataStrings.ALIGNMENT) remains as-is for
parsing/validation, but after that conditional return a sensible default (match
the default used by JsonStructureFieldMetadataNode — e.g., 1) so optional
alignment is handled correctly.

In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicarray/DynamicLengthArrayParser.java:
- Around line 69-72: Null-check the result of
lengthFieldLocation.getAsJsonObject().get(JsonMetadataStrings.PATH) and validate
that when pathElement.isJsonArray() the array size is > 0 before accessing
get(size()-1); if PATH is missing or the array is empty, throw a clear
IllegalArgumentException (or return a sensible default) with context including
the metadata location, and otherwise extract the last element safely to assign
to lengthName; update the logic around lengthFieldLocation, pathElement, and
lengthName in DynamicLengthArrayParser to perform these checks and produce a
meaningful error when the PATH is absent or empty.

In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java:
- Around line 58-70: The thrown ParseException messages in
StaticLengthStringParser reference "Dynamic-length string" incorrectly; update
the three error strings used around the node and fieldClass checks (the messages
thrown when node is not a JsonStructureFieldMemberMetadataNode, when
fieldClassElement is null or not a JsonObject, and when lengthField is null) to
say "Static-length string" (e.g., "Static-length string only supported in JSON
metadata", "Static-length string fieldclass must be a json object.", and
"Static-length string requires length-field-location property") so the messages
correctly reflect the StaticLengthStringParser class.
- Around line 29-43: The class Javadoc is describing dynamic-length strings but
the class is StaticLengthStringParser; update the Javadoc text for
StaticLengthStringParser to describe static-length string fields (fixed byte
length determined by the length property, how NULL bytes are handled as
padding/truncation, and the relation to the length-field-location property if
applicable), making sure the description and examples use the class name
StaticLengthStringParser and reflect static-length semantics instead of
dynamic-length ones.

In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java:
- Around line 201-225: The loop that builds child
JsonStructureFieldMemberMetadataNode instances assumes each memberElement
contains NAME and FIELD_CLASS; add null checks for
memberElement.getAsJsonObject().get(JsonMetadataStrings.NAME) and
.get(JsonMetadataStrings.FIELD_CLASS) and for fieldClass.isJsonObject() before
calling getAsString()/getAsJsonObject(); if any required property is missing or
of the wrong type, throw a ParseException with a clear message; update the
construction site of JsonStructureFieldMemberMetadataNode (in the loop over
memberClasses) to only create and add childNode when those validations pass.

In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java:
- Around line 93-96: The getMaximumSize() implementation in
StaticLengthStringDeclaration is wrong: it returns Integer.MAX_VALUE causing
struct size computations to overflow; change it to return the actual fixed size
(use the declaration's fLength multiplied by Byte.SIZE) so
StaticLengthStringDeclaration#getMaximumSize() mirrors BlobDeclaration's
behavior and makes StructDeclaration.getMaximumSize() sum correct field sizes;
update the method to compute and return fLength * Byte.SIZE.

In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java:
- Around line 203-206: The Javadoc for the PATH constant is incorrect (it
currently reads "Type string for a structure field class"); update the comment
above the public static final String PATH to accurately describe its purpose as
the JSON key for field location paths (used to represent a field's location
path), not a structure field class—use wording consistent with the STRUCTURE
constant comment to avoid the copy/paste error.
🧹 Nitpick comments (17)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition.java (1)

29-29: Incomplete @apiNote and consider formal deprecation.

The annotation text is grammatically incomplete (starts with "as it is"). If the intent is to discourage use of this class, consider:

  1. Fixing the grammar: "This class is too tightly coupled to StringDeclaration. Use StringDefinition2 instead."
  2. Adding a formal @Deprecated annotation if this class should no longer be used, which provides IDE warnings.
📝 Suggested improvement
 * @author Matthew Khouzam
 * @author Simon Marchi
-* @apiNote as it is too coupled to the StringDeclaration class. Use StringDefinition2
+* @apiNote This class is tightly coupled to {@link StringDeclaration}. Consider using {@link StringDefinition2} instead.
 */

Or, if you want to formally deprecate:

 * @author Matthew Khouzam
 * @author Simon Marchi
+* @deprecated This class is tightly coupled to {@link StringDeclaration}. Use {@link StringDefinition2} instead.
 */
+@Deprecated
 public final class StringDefinition extends Definition {
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java (1)

198-206: Consider adding null/empty name guard for consistency with registerType.

The Objects.equals() change is correct. However, registerType now includes a null/empty name check (lines 175-178), while registerIdentifier does not. If a null or empty name is passed here, it will still be inserted into fIdentifiers, potentially causing unexpected behavior.

If anonymous identifiers are not expected, a similar guard would improve consistency and robustness:

Suggested fix
 public void registerIdentifier(String name, IDeclaration declaration) throws ParseException {
+    if (name == null || name.isEmpty()) {
+        // don't register anonymous identifiers
+        return;
+    }
     /* Check if the type has been defined in the current scope */
     IDeclaration iDeclaration = fIdentifiers.get(name);
     if (iDeclaration != null && !Objects.equals(iDeclaration, declaration)) {
         throw new ParseException("Identifier has already been defined:" + name); //$NON-NLS-1$
     }
     /* Add it to the register. */
     fIdentifiers.put(name, declaration);
 }
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDeclaration.java (1)

135-138: Potential integer overflow when converting Long to int.

Line 135 validates tagValue against fFieldArray.length using the Long value, but line 138 converts to int via tagValue.intValue(). If tagValue exceeds Integer.MAX_VALUE, the bounds check passes but intValue() silently truncates, potentially causing an incorrect array index or ArrayIndexOutOfBoundsException.

Given that fFieldArray.length is bounded by int, values ≥ Integer.MAX_VALUE should fail the bounds check in practice, but the logic is fragile. Consider using Math.toIntExact() for safer conversion.

Suggested fix
-                fDeclarationToPopulate = fFieldArray[(tagValue.intValue())];
+                fDeclarationToPopulate = fFieldArray[Math.toIntExact(tagValue)];
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (2)

43-46: Move validation to constructor for fail-fast behavior.

Length bounds checking (lines 69-74) and null-checking encoding should be done here rather than deferring failure to createDefinition(). This prevents creation of invalid declaration objects and provides clearer error attribution.

♻️ Suggested refactor
 public StaticLengthStringDeclaration(int length, Charset encoding) {
+    if (length < 0) {
+        throw new IllegalArgumentException("Length cannot be negative: " + length); //$NON-NLS-1$
+    }
+    if (length > 1_000_000) {
+        throw new IllegalArgumentException("Length cannot exceed 1000000: " + length); //$NON-NLS-1$
+    }
+    if (encoding == null) {
+        throw new IllegalArgumentException("Encoding cannot be null"); //$NON-NLS-1$
+    }
     fLength = length;
     fEncoding = encoding;
 }

67-86: Prefer bulk byte reading for efficiency and clarity.

The per-byte loop (lines 77-79) can be replaced with BitBuffer.get(byte[]) which handles bulk transfer. Additionally, the rawLength variable and its long cast are redundant since fLength is already an int.

♻️ Suggested refactor
 @Override
 public StringDefinition2 createDefinition(@Nullable IDefinitionScope definitionScope, String fieldName, BitBuffer input) throws CTFException {
-    long rawLength = fLength;
-    if (rawLength < 0) {
-        throw new CTFException("Cannot have a length < 0, declared = " + rawLength); //$NON-NLS-1$
-    }
-    if (rawLength > 1e6) {
-        throw new CTFException("Cannot have a length > 1000000, declared = " + rawLength); //$NON-NLS-1$
-    }
-    int length = (int) rawLength;
-    byte[] bytes = new byte[length];
-    for (int i = 0; i < length; i++) {
-        bytes[i] = (byte) input.get(Byte.SIZE, false);
-    }
+    byte[] bytes = new byte[fLength];
+    input.get(bytes);
     String value = new String(bytes, fEncoding);
     int nullIndex = value.indexOf('\0');
     if (nullIndex >= 0) {
         value = value.substring(0, nullIndex);
     }
     return new StringDefinition2(this, definitionScope, fieldName, value);
 }

Note: This assumes validation is moved to the constructor as suggested. The BitBuffer.get(byte[]) method performs bulk transfer efficiently.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java (2)

348-352: Consider null-safety for role parameter.

The setRole override stores the role in fRoles without checking if role is null. If super.setRole(role) accepts null, this could insert a null key into the HashMap.

♻️ Suggested defensive check
 @Override
 public void setRole(String role) {
     super.setRole(role);
-    fRoles.put(role, this);
+    if (role != null) {
+        fRoles.put(role, this);
+    }
 }

422-430: Minor: Javadoc return description is imprecise.

The @return says "the role" but should say "the declaration with the specified role" for clarity.

📝 Suggested Javadoc fix
 /**
  * Get the child with a role
  * @param role the role
- * @return the role
+ * @return the declaration with the specified role, or null if not found
  * @since 5.1
  */
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (1)

202-206: Redundant null/type check.

Line 202 checks memberNode.getFieldClass().isJsonObject(), but lines 203-206 immediately retrieve fieldClassElement and check if it's null or not a JSON object again. This is redundant.

♻️ Suggested simplification
-        } else if (struct instanceof JsonStructureFieldMemberMetadataNode memberNode) {
-            if (memberNode.getFieldClass().isJsonObject()) {
-                JsonElement fieldClassElement = memberNode.getFieldClass();
-                if (fieldClassElement == null || !fieldClassElement.isJsonObject()) {
-                    throw new ParseException(getClass().getName() + " fieldclass must be a json object."); //$NON-NLS-1$
-                }
-                JsonObject outerFieldClass = fieldClassElement.getAsJsonObject();
+        } else if (struct instanceof JsonStructureFieldMemberMetadataNode memberNode) {
+            JsonElement fieldClassElement = memberNode.getFieldClass();
+            if (fieldClassElement == null || !fieldClassElement.isJsonObject()) {
+                throw new ParseException(getClass().getName() + " fieldclass must be a json object."); //$NON-NLS-1$
+            }
+            JsonObject outerFieldClass = fieldClassElement.getAsJsonObject();
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java (3)

672-697: Binary search optimization is partially effective.

The binary search finds the rightmost node with start <= value, but then the backward linear scan from lastValid to 0 (line 690) is O(n) in the worst case (e.g., when all intervals start at 0). This negates the benefit of the binary search for overlapping interval queries.

Consider either:

  1. Breaking early in the backward loop when node.start is far enough below value that no more overlaps are possible
  2. Using an interval tree data structure (augmented BST with max endpoint tracking)

For typical CTF2 enumeration mappings with non-overlapping ranges, this may be acceptable.


170-179: Consider making IntervalNode fields final.

The start, end, and name fields are set only in the constructor and never modified. Marking them final would make the immutability explicit.

 private static class IntervalNode {
-    final long start, end;
-    final String name;
+    private final long start;
+    private final long end;
+    private final String name;

     IntervalNode(long start, long end, String name) {

Note: The fields are already marked final on a single line - just suggesting splitting for clarity.


140-143: Deprecation message could be clearer.

The deprecation notice says to use createDeclaration(...) but doesn't explain why or what specific signature to use. Consider adding @deprecated Javadoc with the specific factory method signature.

     /**
      * Unsigned 5 bit int, used for event headers
-     * @deprecated use the {@link #createDeclaration(int, boolean, int, ByteOrder, Encoding, String, long, String, Map)} instead
+     * @deprecated Use {@link #createDeclaration(int, boolean, int, ByteOrder, Encoding, String, long, String)} 
+     *             or the Map overload to create new IntegerDeclaration instances.
+     *             This constant is deprecated to avoid confusion with dynamic declaration creation.
      */
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java (2)

155-160: Minor inefficiency: redundant getFieldClass() call.

Line 160 calls member.getFieldClass().getAsJsonObject() again after already validating and extracting it to fieldClassElement on lines 156-159. Consider reusing fieldClassElement:

♻️ Suggested fix
         if (fieldClassElement == null || !fieldClassElement.isJsonObject()) {
             throw new ParseException(getClass().getName() + " fieldclass must be a json object."); //$NON-NLS-1$
         }
-        JsonObject fieldclass = member.getFieldClass().getAsJsonObject();
+        JsonObject fieldclass = fieldClassElement.getAsJsonObject();

267-270: LGTM with minor nit: unnecessary blank line.

The updated createDeclaration call with (int) size as the first parameter aligns with the updated method signature.

Consider removing the blank line 268 for consistency with the surrounding code.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java (1)

80-104: Unused Param class.

The Param class is defined but never used in the parse method. Consider either:

  1. Removing it if not needed, or
  2. Using it for trace context if required for future enhancements

This appears to follow the pattern of similar parsers for consistency. If kept for consistency, consider adding a brief comment explaining the intent.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (2)

130-135: Minor inefficiency: redundant getFieldClass() call.

Same issue as in IntegerDeclarationParser - line 135 calls member.getFieldClass().getAsJsonObject() again after already validating it on lines 131-134.

♻️ Suggested fix
         if (fieldClassElement == null || !fieldClassElement.isJsonObject()) {
             throw new ParseException(getClass().getName() + " fieldclass must be a json object."); //$NON-NLS-1$
         }
-        JsonObject fieldclass = member.getFieldClass().getAsJsonObject();
+        JsonObject fieldclass = fieldClassElement.getAsJsonObject();

159-161: Consider passing member instead of floatingPoint for clarity.

While floatingPoint and member reference the same object in this branch, passing member would be more consistent with the pattern and make the code clearer.

         if (fieldclass.has(JsonMetadataStrings.ALIGNMENT)) {
-            alignment = AlignmentParser.INSTANCE.parse(floatingPoint, null);
+            alignment = AlignmentParser.INSTANCE.parse(member, null);
         }
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java (1)

65-66: Consider using imports for cleaner code.

The fully qualified class names work but reduce readability. Consider importing the classes.

♻️ Suggested refactor

Add imports:

import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.integer.IntegerDeclarationParser;

Then simplify the usage:

-        IntegerDeclaration result = org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.integer.IntegerDeclarationParser.INSTANCE.parse(node,
-            new org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.integer.IntegerDeclarationParser.Param(trace));
+        IntegerDeclaration result = IntegerDeclarationParser.INSTANCE.parse(node,
+            new IntegerDeclarationParser.Param(trace));
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 49eb341 and d62c3d1.

📒 Files selected for processing (32)
  • common/org.eclipse.tracecompass.common.core.tests/META-INF/MANIFEST.MF
  • common/org.eclipse.tracecompass.common.core.tests/src/org/eclipse/tracecompass/common/core/tests/log/LoggerTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/META-INF/MANIFEST.MF
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BlobDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/ScopedDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonTraceMetadataNode.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/AlignmentParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicarray/DynamicLengthArrayParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java
  • ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java
  • ctf/org.eclipse.tracecompass.tmf.ctf.ui.swtbot.tests/src/org/eclipse/tracecompass/tmf/ctf/ui/swtbot/tests/TestInvalidCtfTrace.java
🚧 Files skipped from review as they are similar to previous changes (13)
  • common/org.eclipse.tracecompass.common.core.tests/src/org/eclipse/tracecompass/common/core/tests/log/LoggerTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/TypeAliasParserTest.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDefinition.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructDeclarationParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/FloatDeclarationParserTest.java
  • ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/JsonTraceMetadataNodeTest.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java
  • ctf/org.eclipse.tracecompass.tmf.ctf.core/src/org/eclipse/tracecompass/tmf/ctf/core/event/CtfTmfEventField.java
  • common/org.eclipse.tracecompass.common.core.tests/META-INF/MANIFEST.MF
  • ctf/org.eclipse.tracecompass.tmf.ctf.ui.swtbot.tests/src/org/eclipse/tracecompass/tmf/ctf/ui/swtbot/tests/TestInvalidCtfTrace.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticarray/StaticLengthArrayParser.java
  • ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/BlobDeclaration.java
🧰 Additional context used
🧬 Code graph analysis (6)
ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java (2)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMemberMetadataNode.java (1)
  • JsonStructureFieldMemberMetadataNode (31-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java (1)
  • IntegerDeclarationParser (81-275)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (3)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/io/BitBuffer.java (1)
  • BitBuffer (32-743)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/Declaration.java (1)
  • Declaration (30-90)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StringDefinition2.java (1)
  • StringDefinition2 (22-72)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java (1)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/AlignmentParser.java (1)
  • AlignmentParser (56-142)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (3)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMemberMetadataNode.java (1)
  • JsonStructureFieldMemberMetadataNode (31-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMetadataNode.java (1)
  • JsonStructureFieldMetadataNode (29-89)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-269)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java (3)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMemberMetadataNode.java (1)
  • JsonStructureFieldMemberMetadataNode (31-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (1)
  • StaticLengthStringDeclaration (30-111)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-269)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/AlignmentParser.java (3)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMemberMetadataNode.java (1)
  • JsonStructureFieldMemberMetadataNode (31-115)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonStructureFieldMetadataNode.java (1)
  • JsonStructureFieldMetadataNode (29-89)
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)
  • JsonMetadataStrings (25-269)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / build
  • GitHub Check: build / build
  • GitHub Check: build / build
🔇 Additional comments (24)
ctf/org.eclipse.tracecompass.ctf.core.tests/META-INF/MANIFEST.MF (1)

26-31: LGTM!

The com.google.gson import is correctly added to support the new Gson-based JSON parsing for CTF 2 traces. The formatting follows the existing pattern, and omitting the version constraint is consistent with how com.google.common.collect is handled in the same manifest.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/metadata/DeclarationScope.java (1)

175-182: LGTM! Good defensive improvements to type registration.

The null/empty name guard for anonymous types and the idempotent registration pattern using Objects.equals() are solid improvements. This aligns with the existing registerVariant() pattern and supports CTF 2 metadata parsing where the same type definition may be encountered multiple times.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/types/StaticLengthStringDeclaration.java (1)

103-110: LGTM!

The isBinaryEquivalent implementation correctly compares both length and encoding. Using Objects.equal() for the encoding comparison handles null safety appropriately.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonTraceMetadataNode.java (1)

19-19: LGTM! Clean migration from org.json to Gson.

The type change from JSONObject to JsonObject is consistent across the import, field declaration, and getter method. This aligns with the PR's broader adoption of Gson for JSON-based metadata handling.

Also applies to: 33-33, 65-66

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDefinition.java (2)

186-225: LGTM! Well-structured lookup with proper loop prevention.

The enhanced lookupDefinition correctly:

  1. Handles null checks and self-exclusion (lines 188-190)
  2. Uses pattern matching for cleaner instanceof checks (line 206)
  3. Supports role-based lookup via getDeclaration().getRole() (line 208)
  4. Properly passes this when delegating to parent scope (line 222), preventing infinite recursion

236-264: LGTM! Role-based lookup with proper nested structure traversal.

The lookupRole method provides a clean way to find definitions by their role, with:

  • Null safety for the role parameter
  • Direct child lookup followed by recursive search
  • Proper handling of nested StructDefinition and VariantDefinition types
ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/StructDeclaration.java (2)

59-60: LGTM! Role-based declaration storage.

The new fRoles map enables efficient role-based lookup of child declarations, complementing the existing name-based field access.


216-219: Good role population logic.

Correctly stores declarations by role when a field with a non-null, non-empty role is added.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDefinition.java (4)

45-69: LGTM! New constructor for flexible tag types.

The new constructor properly accepts SimpleDatatypeDefinition and follows the same initialization pattern as the existing EnumDefinition constructor. The @since 5.1 annotation correctly documents the API addition.


138-164: LGTM! Enhanced lookup with role-based resolution.

The enhanced lookupDefinition correctly:

  1. Maintains null-safety (line 140-142)
  2. Adds role-based lookup for fTagDef and fDefinition (lines 146-151)
  3. Properly delegates to child ScopedDefinition with exclusion (lines 152-157)
  4. Passes this when delegating to parent StructDefinition to prevent infinite loops (line 161)

166-192: LGTM! Overload maintains consistent lookup semantics.

The new overload correctly propagates the definitionToExclude parameter through the lookup chain and mirrors the single-argument version's behavior.


39-39: Field type broadened to support non-enum tags.

Changing fTagDef from EnumDefinition to SimpleDatatypeDefinition enables more flexible tag types while maintaining backward compatibility. EnumDefinition extends SimpleDatatypeDefinition, so existing code using the EnumDefinition constructor remains compatible.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java (1)

16-268: LGTM overall for the new constants.

The new string constants for CTF2 field classes (floating point, strings, arrays, encoding, alignment, byte order) are well-organized and properly documented with Javadoc. These provide a clean centralized location for JSON metadata keys.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/AlignmentParser.java (1)

99-106: LGTM for JsonStructureFieldMetadataNode handling.

The pattern matching with instanceof is clean and properly validates alignment before returning.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java (1)

193-200: LGTM for JsonStructureFieldMetadataNode branch.

The handling for JsonStructureFieldMetadataNode correctly extracts minimum alignment and sets up the struct body when member classes are present.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/dynamicarray/DynamicLengthArrayParser.java (1)

44-80: LGTM for overall parser structure.

The parser follows the established singleton pattern with a Param class, validates input types appropriately, and correctly delegates element type resolution to TypeAliasParser. The error messages are descriptive and helpful for debugging.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/IntegerDeclaration.java (2)

408-424: LGTM for setMappings and buildIntervalTree.

The implementation correctly clears existing mappings before adding new ones, and builds the interval tree sorted by start position for efficient lookup.


586-588: LGTM for the refactoring changes.

  • Using Long.SIZE instead of a magic number improves readability
  • Including fMappings and getRole() in hashCode/equals ensures proper equality semantics for the new mapping feature

Also applies to: 604-604, 631-636

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/integer/IntegerDeclarationParser.java (1)

198-200: LGTM!

The delegation to AlignmentParser.INSTANCE.parse(member, null) is correct. The AlignmentParser handles JsonStructureFieldMemberMetadataNode and extracts alignment from the field class internally.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java (1)

72-77: LGTM!

The encoding handling with fallback to UTF-8 and the StaticLengthStringDeclaration construction are correct.

ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/floatingpoint/FloatDeclarationParser.java (3)

137-152: LGTM!

The IEEE 754 size mappings are correct:

  • 32-bit (single precision): exponent=8, mantissa=24
  • 64-bit (double precision): exponent=11, mantissa=53

The TODO for 16-bit (half precision) and extended precision formats is appropriately documented.


162-199: LGTM!

The legacy (non-JSON) parsing path is correctly preserved within the else branch.


200-211: LGTM!

The final size validation and default alignment handling are correct.

ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/types/CTF2IntegrationTest.java (1)

37-74: LGTM!

Good integration test that validates the JSON-based integer parsing with mappings. The test properly:

  • Constructs the JSON structure matching CTF2 format
  • Verifies the parsed result has correct length, mappings count, and mapping keys

Comment on lines +47 to 49
private final Map<String, IDeclaration> fFields = new HashMap<>();
private IDeclaration[] fFieldArray = new IDeclaration[0];
private IDeclaration fDeclarationToPopulate;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Race condition: fDeclarationToPopulate should be a local variable.

fDeclarationToPopulate is an instance field that gets assigned during createDefinition (lines 133, 138, 150). If two threads call createDefinition concurrently on the same VariantDeclaration instance, they will overwrite each other's value, causing incorrect field resolution.

This should be refactored to a local variable within createDefinition.

Additionally, changing from a synchronized HashMap to a plain HashMap removes thread-safety guarantees. Verify whether concurrent access to this class is expected.

Proposed fix for the race condition
-    private IDeclaration fDeclarationToPopulate;

Then in createDefinition, declare it as a local variable:

IDeclaration declarationToPopulate = null;
// ... use declarationToPopulate instead of fDeclarationToPopulate throughout the method
🤖 Prompt for AI Agents
In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDeclaration.java
around lines 47 - 49, The field fDeclarationToPopulate is used only within
createDefinition and causes a race when multiple threads call createDefinition
on the same VariantDeclaration; make fDeclarationToPopulate a local variable
inside createDefinition (replace uses of fDeclarationToPopulate with a local
IDeclaration declarationToPopulate) and update all assignments and references in
that method accordingly; also review the change from a synchronized map to a
plain HashMap for fFields and, if concurrent access is expected, restore
thread-safety (e.g., use Collections.synchronizedMap, ConcurrentHashMap, or
synchronize access around fFields) to avoid concurrent modification issues.

Comment on lines +128 to +139
if (def instanceof IntegerDefinition) {
tagDef = (SimpleDatatypeDefinition) def;
Long tagValue = ((IntegerDefinition) tagDef).getIntegerValue();
String mappings = ((IntegerDefinition) tagDef).getMappings();
if (mappings != null) {
fDeclarationToPopulate = fFields.get(mappings);
} else if (tagValue != null) {
if (tagValue < 0 || tagValue >= fFieldArray.length) {
throw new CTFException("Unknown value of " + tagValue + " for the variant " + toString()); //$NON-NLS-1$ //$NON-NLS-2$
}
fDeclarationToPopulate = fFieldArray[(tagValue.intValue())];
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing handling when both mappings and tagValue are null.

If def is an IntegerDefinition but both getMappings() returns null and getIntegerValue() returns null, then fDeclarationToPopulate is never assigned in this branch. The code falls through to line 152 which throws an exception with "Unknown enum selector" — a misleading message for an integer-based tag.

Consider adding explicit handling or an appropriate error message for this edge case.

Suggested fix
             if (mappings != null) {
                 fDeclarationToPopulate = fFields.get(mappings);
             } else if (tagValue != null) {
                 if (tagValue < 0 || tagValue >= fFieldArray.length) {
                     throw new CTFException("Unknown value of " + tagValue + " for the variant " + toString()); //$NON-NLS-1$ //$NON-NLS-2$
                 }
                 fDeclarationToPopulate = fFieldArray[(tagValue.intValue())];
+            } else {
+                throw new CTFException("Integer tag has no value or mappings for variant " + toString()); //$NON-NLS-1$
             }
🤖 Prompt for AI Agents
In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDeclaration.java
around lines 128 - 139, The IntegerDefinition branch in VariantDeclaration
(where def instanceof IntegerDefinition, tagDef, getMappings(),
getIntegerValue()) doesn't handle the case where both mappings and tagValue are
null, so fDeclarationToPopulate can remain unset and later produce a misleading
"Unknown enum selector" error; update that branch to explicitly detect
mappings==null && tagValue==null and throw a CTFException with a clear message
(e.g., "Missing integer tag value or mappings for variant " + toString()) or
otherwise set fDeclarationToPopulate to a sensible default before falling
through, ensuring the exception refers to an integer-based tag and using the
existing identifiers tagDef, fDeclarationToPopulate, getMappings(), and
getIntegerValue().

Comment on lines 168 to 173
public void addField(String fieldTag, IDeclaration declaration) {
fFields.put(fieldTag, declaration);
int size = fFields.size();
fFieldArray = Arrays.copyOf(fFieldArray, size);
fFieldArray[size - 1] = declaration;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Bug: fFieldArray becomes inconsistent when a field is overwritten.

If addField is called with a fieldTag that already exists in fFields, HashMap.put() replaces the value but fFields.size() remains unchanged. However, the code still appends to fFieldArray, causing:

  1. fFieldArray grows larger than fFields.size()
  2. The old declaration remains in fFieldArray at its original index
  3. Index-based lookups in createDefinition may return stale declarations

Example sequence:

addField("a", decl1);  // fFields={"a":decl1}, fFieldArray=[decl1]
addField("b", decl2);  // fFields={"a":decl1,"b":decl2}, fFieldArray=[decl1,decl2]
addField("a", decl3);  // fFields={"a":decl3,"b":decl2}, fFieldArray=[decl1,decl2,decl3]
// Index 0 lookup returns decl1, but fFields.get("a") returns decl3
Suggested fix
 public void addField(String fieldTag, IDeclaration declaration) {
+    boolean isNewField = !fFields.containsKey(fieldTag);
     fFields.put(fieldTag, declaration);
-    int size = fFields.size();
-    fFieldArray = Arrays.copyOf(fFieldArray, size);
-    fFieldArray[size - 1] = declaration;
+    if (isNewField) {
+        int size = fFields.size();
+        fFieldArray = Arrays.copyOf(fFieldArray, size);
+        fFieldArray[size - 1] = declaration;
+    }
 }

Note: This fix only handles new fields. If overwriting is expected, you'll need to track indices or use a LinkedHashMap to maintain consistent ordering.

🤖 Prompt for AI Agents
In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/ctf/core/event/types/VariantDeclaration.java
around lines 168 - 173, addField currently always appends to fFieldArray after
fFields.put, so overwriting an existing fieldTag makes fFieldArray inconsistent
with fFields and breaks index-based lookups in createDefinition; change addField
to detect whether the key already existed (e.g. check
fFields.containsKey(fieldTag) or capture the previous value from fFields.put)
and if it did, find and replace the existing entry in fFieldArray (or rebuild
fFieldArray from fFields.values()) instead of blindly growing the array; ensure
createDefinition continues to rely on the corrected fFieldArray ordering.

Comment on lines +107 to 126
} else if (tree instanceof JsonStructureFieldMemberMetadataNode structTree) {
JsonElement fieldClassElement = structTree.getFieldClass();
if (fieldClassElement == null || !fieldClassElement.isJsonObject()) {
throw new ParseException(getClass().getName() + " fieldclass must be a json object."); //$NON-NLS-1$
}
JsonObject fieldclass = fieldClassElement.getAsJsonObject();
if (fieldclass.has(JsonMetadataStrings.ALIGNMENT)) {
JsonElement alignmentElement = fieldclass.get(JsonMetadataStrings.ALIGNMENT);
if (alignmentElement == null || !alignmentElement.isJsonPrimitive()) {
throw new ParseException(INVALID_VALUE_FOR_ALIGNMENT + " : " //$NON-NLS-1$
+ alignmentElement);
}
long alignment = alignmentElement.getAsLong();
if (!isValidAlignment(alignment)) {
throw new ParseException(INVALID_VALUE_FOR_ALIGNMENT + " : " //$NON-NLS-1$
+ alignment);
}
return alignment;
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing return for optional alignment case.

When parsing a JsonStructureFieldMemberMetadataNode, if the ALIGNMENT field is not present in the field class, the method falls through to throw a ParseException at line 128. However, alignment may be optional in CTF2 metadata, with a default value (typically 1 or 8 depending on context).

Consider returning a default alignment when the field is absent, similar to how JsonStructureFieldMetadataNode handles minimum alignment:

             if (fieldclass.has(JsonMetadataStrings.ALIGNMENT)) {
                 JsonElement alignmentElement = fieldclass.get(JsonMetadataStrings.ALIGNMENT);
                 if (alignmentElement == null || !alignmentElement.isJsonPrimitive()) {
                     throw new ParseException(INVALID_VALUE_FOR_ALIGNMENT + " : " //$NON-NLS-1$
                             + alignmentElement);
                 }
                 long alignment = alignmentElement.getAsLong();
                 if (!isValidAlignment(alignment)) {
                     throw new ParseException(INVALID_VALUE_FOR_ALIGNMENT + " : " //$NON-NLS-1$
                             + alignment);
                 }
                 return alignment;
             }
+            // Return default alignment when not specified
+            return 1L;
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} else if (tree instanceof JsonStructureFieldMemberMetadataNode structTree) {
JsonElement fieldClassElement = structTree.getFieldClass();
if (fieldClassElement == null || !fieldClassElement.isJsonObject()) {
throw new ParseException(getClass().getName() + " fieldclass must be a json object."); //$NON-NLS-1$
}
JsonObject fieldclass = fieldClassElement.getAsJsonObject();
if (fieldclass.has(JsonMetadataStrings.ALIGNMENT)) {
JsonElement alignmentElement = fieldclass.get(JsonMetadataStrings.ALIGNMENT);
if (alignmentElement == null || !alignmentElement.isJsonPrimitive()) {
throw new ParseException(INVALID_VALUE_FOR_ALIGNMENT + " : " //$NON-NLS-1$
+ alignmentElement);
}
long alignment = alignmentElement.getAsLong();
if (!isValidAlignment(alignment)) {
throw new ParseException(INVALID_VALUE_FOR_ALIGNMENT + " : " //$NON-NLS-1$
+ alignment);
}
return alignment;
}
}
} else if (tree instanceof JsonStructureFieldMemberMetadataNode structTree) {
JsonElement fieldClassElement = structTree.getFieldClass();
if (fieldClassElement == null || !fieldClassElement.isJsonObject()) {
throw new ParseException(getClass().getName() + " fieldclass must be a json object."); //$NON-NLS-1$
}
JsonObject fieldclass = fieldClassElement.getAsJsonObject();
if (fieldclass.has(JsonMetadataStrings.ALIGNMENT)) {
JsonElement alignmentElement = fieldclass.get(JsonMetadataStrings.ALIGNMENT);
if (alignmentElement == null || !alignmentElement.isJsonPrimitive()) {
throw new ParseException(INVALID_VALUE_FOR_ALIGNMENT + " : " //$NON-NLS-1$
alignmentElement);
}
long alignment = alignmentElement.getAsLong();
if (!isValidAlignment(alignment)) {
throw new ParseException(INVALID_VALUE_FOR_ALIGNMENT + " : " //$NON-NLS-1$
alignment);
}
return alignment;
}
// Return default alignment when not specified
return 1L;
}
🤖 Prompt for AI Agents
In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/AlignmentParser.java
around lines 107 - 126, In the JsonStructureFieldMemberMetadataNode branch of
AlignmentParser (the else-if handling JsonStructureFieldMemberMetadataNode), add
a return of the default alignment when the fieldclass does not contain
JsonMetadataStrings.ALIGNMENT instead of falling through to the ParseException;
specifically: if fieldclass.has(JsonMetadataStrings.ALIGNMENT) remains as-is for
parsing/validation, but after that conditional return a sensible default (match
the default used by JsonStructureFieldMetadataNode — e.g., 1) so optional
alignment is handled correctly.

Comment on lines +58 to +70
if (!(node instanceof JsonStructureFieldMemberMetadataNode)) {
throw new ParseException("Dynamic-length string only supported in JSON metadata"); //$NON-NLS-1$
}

JsonStructureFieldMemberMetadataNode member = (JsonStructureFieldMemberMetadataNode) node;
JsonElement fieldClassElement = member.getFieldClass();
if (fieldClassElement == null || !fieldClassElement.isJsonObject()) {
throw new ParseException(getClass().getName() + " fieldclass must be a json object."); //$NON-NLS-1$
}
JsonObject fieldClass = fieldClassElement.getAsJsonObject();
JsonElement lengthField = fieldClass.get(JsonMetadataStrings.LENGTH);
if (lengthField == null) {
throw new ParseException("Dynamic-length string requires length-field-location property"); //$NON-NLS-1$
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix error messages: reference static-length, not dynamic-length.

The error messages incorrectly reference "Dynamic-length string" but this is a static-length string parser.

📝 Suggested fix
         if (!(node instanceof JsonStructureFieldMemberMetadataNode)) {
-            throw new ParseException("Dynamic-length string only supported in JSON metadata"); //$NON-NLS-1$
+            throw new ParseException("Static-length string only supported in JSON metadata"); //$NON-NLS-1$
         }
         // ...
         if (lengthField == null) {
-            throw new ParseException("Dynamic-length string requires length-field-location property"); //$NON-NLS-1$
+            throw new ParseException("Static-length string requires length property"); //$NON-NLS-1$
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!(node instanceof JsonStructureFieldMemberMetadataNode)) {
throw new ParseException("Dynamic-length string only supported in JSON metadata"); //$NON-NLS-1$
}
JsonStructureFieldMemberMetadataNode member = (JsonStructureFieldMemberMetadataNode) node;
JsonElement fieldClassElement = member.getFieldClass();
if (fieldClassElement == null || !fieldClassElement.isJsonObject()) {
throw new ParseException(getClass().getName() + " fieldclass must be a json object."); //$NON-NLS-1$
}
JsonObject fieldClass = fieldClassElement.getAsJsonObject();
JsonElement lengthField = fieldClass.get(JsonMetadataStrings.LENGTH);
if (lengthField == null) {
throw new ParseException("Dynamic-length string requires length-field-location property"); //$NON-NLS-1$
if (!(node instanceof JsonStructureFieldMemberMetadataNode)) {
throw new ParseException("Static-length string only supported in JSON metadata"); //$NON-NLS-1$
}
JsonStructureFieldMemberMetadataNode member = (JsonStructureFieldMemberMetadataNode) node;
JsonElement fieldClassElement = member.getFieldClass();
if (fieldClassElement == null || !fieldClassElement.isJsonObject()) {
throw new ParseException(getClass().getName() + " fieldclass must be a json object."); //$NON-NLS-1$
}
JsonObject fieldClass = fieldClassElement.getAsJsonObject();
JsonElement lengthField = fieldClass.get(JsonMetadataStrings.LENGTH);
if (lengthField == null) {
throw new ParseException("Static-length string requires length property"); //$NON-NLS-1$
🤖 Prompt for AI Agents
In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/staticstring/StaticLengthStringParser.java
around lines 58 - 70, The thrown ParseException messages in
StaticLengthStringParser reference "Dynamic-length string" incorrectly; update
the three error strings used around the node and fieldClass checks (the messages
thrown when node is not a JsonStructureFieldMemberMetadataNode, when
fieldClassElement is null or not a JsonObject, and when lengthField is null) to
say "Static-length string" (e.g., "Static-length string only supported in JSON
metadata", "Static-length string fieldclass must be a json object.", and
"Static-length string requires length-field-location property") so the messages
correctly reflect the StaticLengthStringParser class.

Comment on lines +201 to +225
} else if (struct instanceof JsonStructureFieldMemberMetadataNode memberNode) {
if (memberNode.getFieldClass().isJsonObject()) {
JsonElement fieldClassElement = memberNode.getFieldClass();
if (fieldClassElement == null || !fieldClassElement.isJsonObject()) {
throw new ParseException(getClass().getName() + " fieldclass must be a json object."); //$NON-NLS-1$
}
JsonObject outerFieldClass = fieldClassElement.getAsJsonObject();
JsonElement minimumAlignment = outerFieldClass.get(JsonMetadataStrings.MINIMUM_ALIGNMENT);
if (minimumAlignment != null) {
structAlign = minimumAlignment.getAsLong();
}
JsonElement memberClasses = outerFieldClass.get(JsonMetadataStrings.MEMBER_CLASSES);
if (memberClasses != null && memberClasses.isJsonArray()) {
hasBody = true;
for (JsonElement memberElement : memberClasses.getAsJsonArray()) {
if (memberElement.isJsonObject()) {
String name = memberElement.getAsJsonObject().get(JsonMetadataStrings.NAME).getAsString();
JsonElement fieldClass = memberElement.getAsJsonObject().get(JsonMetadataStrings.FIELD_CLASS);
JsonStructureFieldMemberMetadataNode childNode = new JsonStructureFieldMemberMetadataNode(memberNode, "", "", name, fieldClass.getAsJsonObject()); //$NON-NLS-1$ //$NON-NLS-2$
memberNode.addChild(childNode);
}
}
structBody = memberNode;
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing null checks for required JSON properties.

The code assumes NAME and FIELD_CLASS properties always exist in each member element without validation. This could cause NullPointerException if either property is missing from malformed metadata.

🔧 Suggested fix with null checks
                 if (memberClasses != null && memberClasses.isJsonArray()) {
                     hasBody = true;
                     for (JsonElement memberElement : memberClasses.getAsJsonArray()) {
                         if (memberElement.isJsonObject()) {
-                            String name = memberElement.getAsJsonObject().get(JsonMetadataStrings.NAME).getAsString();
-                            JsonElement fieldClass = memberElement.getAsJsonObject().get(JsonMetadataStrings.FIELD_CLASS);
-                            JsonStructureFieldMemberMetadataNode childNode = new JsonStructureFieldMemberMetadataNode(memberNode, "", "", name, fieldClass.getAsJsonObject()); //$NON-NLS-1$ //$NON-NLS-2$
+                            JsonObject memberObj = memberElement.getAsJsonObject();
+                            JsonElement nameElement = memberObj.get(JsonMetadataStrings.NAME);
+                            JsonElement fieldClass = memberObj.get(JsonMetadataStrings.FIELD_CLASS);
+                            if (nameElement == null || fieldClass == null || !fieldClass.isJsonObject()) {
+                                throw new ParseException("Member class requires 'name' and 'field-class' properties"); //$NON-NLS-1$
+                            }
+                            String name = nameElement.getAsString();
+                            JsonStructureFieldMemberMetadataNode childNode = new JsonStructureFieldMemberMetadataNode(memberNode, "", "", name, fieldClass.getAsJsonObject()); //$NON-NLS-1$ //$NON-NLS-2$
                             memberNode.addChild(childNode);
                         }
                     }
🤖 Prompt for AI Agents
In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/struct/StructParser.java
around lines 201 - 225, The loop that builds child
JsonStructureFieldMemberMetadataNode instances assumes each memberElement
contains NAME and FIELD_CLASS; add null checks for
memberElement.getAsJsonObject().get(JsonMetadataStrings.NAME) and
.get(JsonMetadataStrings.FIELD_CLASS) and for fieldClass.isJsonObject() before
calling getAsString()/getAsJsonObject(); if any required property is missing or
of the wrong type, throw a ParseException with a clear message; update the
construction site of JsonStructureFieldMemberMetadataNode (in the loop over
memberClasses) to only create and add childNode when those validations pass.

Comment on lines +203 to +206
/**
* Type string for a structure field class
*/
public static final String PATH = "path"; //$NON-NLS-1$
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Incorrect Javadoc for PATH constant.

The Javadoc comment says "Type string for a structure field class" but PATH is used for field location paths, not structure field classes. This appears to be a copy-paste error from the STRUCTURE constant below it.

-    /**
-     * Type string for a structure field class
-     */
+    /**
+     * Field string for the path property in field locations
+     */
     public static final String PATH = "path"; //$NON-NLS-1$
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* Type string for a structure field class
*/
public static final String PATH = "path"; //$NON-NLS-1$
/**
* Field string for the path property in field locations
*/
public static final String PATH = "path"; //$NON-NLS-1$
🤖 Prompt for AI Agents
In
@ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java
around lines 203 - 206, The Javadoc for the PATH constant is incorrect (it
currently reads "Type string for a structure field class"); update the comment
above the public static final String PATH to accurately describe its purpose as
the JSON key for field location paths (used to represent a field's location
path), not a structure field class—use wording consistent with the STRUCTURE
constant comment to avoid the copy/paste error.

Comment on lines +220 to +222
public static final Map<String, Charset> ENCODINGS = Map.of("utf-8",StandardCharsets.UTF_8, //$NON-NLS-1$
"utf-16be",StandardCharsets.UTF_16BE,"utf-16le",StandardCharsets.UTF_16LE, //$NON-NLS-1$ //$NON-NLS-2$
"utf-32be", Charset.forName("UTF-32BE"),"utf-32le", Charset.forName("UTF-32LE")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
Copy link

@coderabbitai coderabbitai bot Jan 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Java UTF-32 charset support specification mandatory optional

💡 Result:

Short answer: Historically UTF‑32 was optional; recent Java SE docs list UTF‑32 (and UTF‑32BE/LE and BOM variants) among the standard charsets that implementations must support. See the Charset API in older JDK docs (required set did not include UTF‑32) vs current API/docs which include UTF‑32. [1][2]

Sources:

  • Charset API (Java SE 11) — standard required charsets (no UTF‑32 listed). [1]
  • Charset API (Java SE 24 / 24+ JDK docs) — lists UTF‑32, UTF‑32BE and UTF‑32LE as standard charsets required of every implementation. [2]

References:
[1] java.nio.charset.Charset (Java SE 11) — Standard charsets.
[2] java.nio.charset.Charset (Java SE 24 / JDK 24) — Standard charsets (includes UTF‑32 variants).


🌐 Web query:

Charset.forName UTF-32BE UTF-32LE UnsupportedCharsetException Java implementations

💡 Result:

Short answer: Charset.forName("UTF-32BE") and Charset.forName("UTF-32LE") will work on modern Oracle/OpenJDK builds (they are listed as standard/available encodings), but they can throw UnsupportedCharsetException on older JVMs where UTF-32 charsets were not provided. You should check at runtime with Charset.isSupported(...) or catch UnsupportedCharsetException if you must run on varied/older JREs. [1][2][3]

References

  • Java Charset spec / list of standard charsets (shows UTF-32BE/UTF-32LE). [1]
  • Oracle "Supported Encodings" page listing UTF-32BE/UTF-32LE entries. [2]
  • OpenJDK bug/CSR showing UTF-32 charsets were added to the JDK (track/fix). [3]

Links:
[1] Oracle Charset API (Java SE).
[2] Oracle Supported Encodings (JDK 22/21 pages).
[3] OpenJDK bug JDK-8310047 (UTF-32 charset addition).


🌐 Web query:

Java character encoding mandatory charsets specification StandardCharsets

💡 Result:

Java requires that every Java platform implementation support these standard charsets (available as constants in java.nio.charset.StandardCharsets):

  • US-ASCII
  • ISO-8859-1
  • UTF-8
  • UTF-16BE
  • UTF-16LE
  • UTF-16

(These are the "standard charsets" guaranteed on every implementation; see StandardCharsets and Charset documentation.) [1][2]

Sources:
[1] Java SE Charset — standard charsets list (Oracle Javadoc).
[2] java.nio.charset.StandardCharsets (Oracle Javadoc).


Ensure UTF-32 charset availability before class loading or add defensive handling.

Charset.forName("UTF-32BE") and Charset.forName("UTF-32LE") may throw UnsupportedCharsetException on Java SE 11 and earlier, where UTF-32 support is not guaranteed by the specification. While Java SE 24+ mandates UTF-32 support, this code's static initializer will cause class loading failure if the charset is unavailable on older JVMs.

Consider either:

  1. Adding a static initializer block with try-catch and fallback
  2. Using lazy initialization instead of static initializer
  3. Documenting the minimum Java version requirement (Java SE 24+, or check for older versions)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a problem for future iterations. I am willing to bet nobody will use utf-32

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MatthewKhouzam, understood! That's a reasonable pragmatic choice given the low likelihood of UTF-32 usage in practice. The static initialization will work fine on modern JVMs, and if it becomes an issue in the future, you can address it then.

Thanks for the clarification!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants