This solution is both: slightly shorter and, more importantly, more efficient due to the use of keys:
<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:key name="kPhraseByMorse" 
           match="*[not(self::silence) and not(self::message)]" 
           use="generate-id(preceding-sibling::silence[1])"/>
    <xsl:template match="/">
      <complexMessage>
        <word>
          <xsl:call-template name="makeCode"/>
        </word>
        <xsl:apply-templates select="*/silence"/>
      </complexMessage>
    </xsl:template>
    <xsl:template match="silence">
      <word>
     <xsl:call-template name="makeCode">
       <xsl:with-param name="pId" select="generate-id()"/>
     </xsl:call-template>
      </word>
    </xsl:template>
    <xsl:template name="makeCode">
      <xsl:param name="pId"/>
      <xsl:attribute name="code">
        <xsl:apply-templates select="key('kPhraseByMorse', $pId)"/>
      </xsl:attribute>
    </xsl:template>
    <xsl:template match="dot">.</xsl:template>
    <xsl:template match="line">-</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided source XML, the correct result is produced:
<complexMessage>
   <word code="-"/>
   <word code=".--"/>
   <word code="."/>
   <word code="-..."/>
</complexMessage>