@@ -579,7 +579,17 @@ private static void ProcessAlternatives(EncodedTextWriter writer, IClass umlClas
579579
580580 if ( targetProperty != null )
581581 {
582- writer . WriteSafeString ( $ "if(poco.{ targetProperty . QueryPropertyNameBasedOnUmlProperties ( ) } .Count == 0){ Environment . NewLine } ") ;
582+ // Use cursor state for ';' vs '{' decision. By the time the body
583+ // is reached, previous methods (prefix, declaration) have already
584+ // consumed typing, multiplicity, etc. from the shared cursor.
585+ // GetOrCreateCursor returns the same cursor at its current position.
586+ // Use cursor state for ';' vs '{' decision. Previous methods
587+ // (prefix, declaration) have consumed typing/multiplicity from
588+ // the shared cursor via GetOrCreateCursor. If cursor.Current is
589+ // null, no body members remain → emit ';'.
590+ var bodyPropertyAccess = targetProperty . QueryPropertyNameBasedOnUmlProperties ( ) ;
591+ writer . WriteSafeString ( $ "if(cursorCache.GetOrCreateCursor(poco.Id, \" { targetProperty . Name } \" , poco.{ bodyPropertyAccess } ).Current == null){ Environment . NewLine } ") ;
592+
583593 writer . WriteSafeString ( $ "{{{Environment.NewLine}") ;
584594 writer . WriteSafeString ( $ "stringBuilder.AppendLine(\" { terminalValue } \" );{ Environment . NewLine } ") ;
585595 writer . WriteSafeString ( $ "}}{ Environment . NewLine } ") ;
@@ -627,7 +637,8 @@ private static void ProcessAlternatives(EncodedTextWriter writer, IClass umlClas
627637 {
628638 var propertyAccessName = targetProperty . QueryPropertyNameBasedOnUmlProperties ( ) ;
629639
630- writer . WriteSafeString ( $ "if(poco.{ propertyAccessName } .Count == 0){ Environment . NewLine } ") ;
640+ writer . WriteSafeString ( $ "if(cursorCache.GetOrCreateCursor(poco.Id, \" { targetProperty . Name } \" , poco.{ propertyAccessName } ).Current == null){ Environment . NewLine } ") ;
641+
631642 writer . WriteSafeString ( $ "{{{Environment.NewLine}") ;
632643 writer . WriteSafeString ( $ "stringBuilder.AppendLine(\" { terminalValue } \" );{ Environment . NewLine } ") ;
633644 writer . WriteSafeString ( $ "}}{ Environment . NewLine } ") ;
@@ -721,7 +732,8 @@ private static void ProcessAlternatives(EncodedTextWriter writer, IClass umlClas
721732 {
722733 var propertyAccessName = targetProperty . QueryPropertyNameBasedOnUmlProperties ( ) ;
723734
724- writer . WriteSafeString ( $ "if(poco.{ propertyAccessName } .Count == 0){ Environment . NewLine } ") ;
735+ writer . WriteSafeString ( $ "if(cursorCache.GetOrCreateCursor(poco.Id, \" { targetProperty . Name } \" , poco.{ propertyAccessName } ).Current == null){ Environment . NewLine } ") ;
736+
725737 writer . WriteSafeString ( $ "{{{Environment.NewLine}") ;
726738 writer . WriteSafeString ( $ "stringBuilder.AppendLine(\" { terminalValue } \" );{ Environment . NewLine } ") ;
727739 writer . WriteSafeString ( $ "}}{ Environment . NewLine } ") ;
@@ -2846,6 +2858,27 @@ private static string ResolveContentTypeGuard(string cursorVariableName, Textual
28462858
28472859 if ( complementaryProperty == null )
28482860 {
2861+ // No complementary composite property exists on this class (e.g., Usage is not
2862+ // a Relationship). Follow the rule's same-property assignment one level deeper:
2863+ // if the rule has ownedRelationship += PrefixMetadataMember, recurse into
2864+ // PrefixMetadataMember which IS a Relationship and has ownedRelatedElement.
2865+ var samePropertyAssignment = referencedRule . Alternatives
2866+ . SelectMany ( alt => alt . Elements )
2867+ . OfType < AssignmentElement > ( )
2868+ . FirstOrDefault ( a => ( a . Operator == "+=" || a . Operator == "=" )
2869+ && string . Equals ( a . Property , outerPropertyName , StringComparison . OrdinalIgnoreCase )
2870+ && a . Value is NonTerminalElement ) ;
2871+
2872+ if ( samePropertyAssignment ? . Value is NonTerminalElement innerNonTerminal )
2873+ {
2874+ var innerRule = ruleGenerationContext . AllRules . SingleOrDefault ( x => x . RuleName == innerNonTerminal . Name ) ;
2875+
2876+ if ( innerRule != null )
2877+ {
2878+ return ResolveContentTypeGuard ( cursorVariableName , innerRule , outerPropertyName , umlClass , ruleGenerationContext ) ;
2879+ }
2880+ }
2881+
28492882 return null ;
28502883 }
28512884
@@ -3088,7 +3121,7 @@ private static void DeclareCursorIfRequired(EncodedTextWriter writer, IClass uml
30883121 /// Terminals after which no trailing space should be emitted,
30893122 /// because the next element is directly adjacent (e.g., content inside angle brackets, closing angle bracket, or the <c>~</c> prefix operator).
30903123 /// </summary>
3091- private static readonly HashSet < string > NoTrailingSpaceTerminals = [ "<" , ">" , "~" ] ;
3124+ private static readonly HashSet < string > NoTrailingSpaceTerminals = [ "<" , ">" , "~" , "[" , "(" , "#" , "." , "'" , "*" ] ;
30923125
30933126 /// <summary>
30943127 /// Writes the <c>stringBuilder.Append</c> or <c>stringBuilder.AppendLine</c> call for a terminal value,
@@ -3128,7 +3161,7 @@ private static void WriteTerminalAppend(EncodedTextWriter writer, string termina
31283161 return ;
31293162 }
31303163
3131- writer . WriteSafeString ( $ "stringBuilder.Append(\" { terminalValue } \" );") ;
3164+ writer . WriteSafeString ( $ "stringBuilder.Append(\" { terminalValue } \" );") ;
31323165 }
31333166
31343167 /// <summary>
0 commit comments