Repository: asciidoctor/asciidoctor (Ruby)

Issue:
Processor crashes if an attrlist is present on a literal monospace phrase (aka codespan)
If an attrlist is added to a literal monospace phrase (aka codespan), the processor crashes. This happens because the attrlist String is passed to a method that assumes it's receiving a Hash.

Example:

```
[.bar]`+foo+`
```

This issue didn't affect v1.5.8 because, although the wrong type was passed, the processor never called a Hash-specific method on it. Since 2.0.0, it does.


Discussion:

Patch:
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index 5541759394..0699eb4025 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -13,6 +13,12 @@ endif::[]
 This document provides a high-level view of the changes introduced in Asciidoctor by release.
 For a detailed view of what has changed, refer to the {uri-repo}/commits/master[commit history] on GitHub.
 
+== Unreleased
+
+Bug Fixes::
+
+  * fix crash when attrlist is used on literal monospace phrase (#3216)
+
 == 2.0.2 (2019-03-26) - @mojavelinux
 
 Bug Fixes::
diff --git a/lib/asciidoctor/substitutors.rb b/lib/asciidoctor/substitutors.rb
index 79a3e42569..757b9343ca 100644
--- a/lib/asciidoctor/substitutors.rb
+++ b/lib/asciidoctor/substitutors.rb
@@ -1064,7 +1064,7 @@ def extract_passthroughs text
 
       if attributes
         if format_mark == '`' && !old_behavior
-          next extract_inner_passthrough content, %(#{preceding}[#{attributes}]#{escape_mark}), attributes
+          next extract_inner_passthrough content, %(#{preceding}[#{attributes}]#{escape_mark})
         elsif escape_mark
           # honor the escape of the formatting mark
           next %(#{preceding}[#{attributes}]#{quoted_text.slice 1, quoted_text.length})
@@ -1371,14 +1371,12 @@ def restore_callouts source, callout_marks, source_offset = nil
   end
 
   # Internal: Extract nested single-plus passthrough; otherwise return unprocessed
-  def extract_inner_passthrough text, pre, attributes = nil
+  def extract_inner_passthrough text, pre
     if (text.end_with? '+') && (text.start_with? '+', '\+') && SinglePlusInlinePassRx =~ text
       if $1
         %(#{pre}`+#{$2}+`)
       else
-        @passthroughs[passthru_key = @passthroughs.size] = attributes ?
-            { text: $2, subs: BASIC_SUBS, attributes: attributes, type: :unquoted } :
-            { text: $2, subs: BASIC_SUBS }
+        @passthroughs[passthru_key = @passthroughs.size] = { text: $2, subs: BASIC_SUBS }
         %(#{pre}`#{PASS_START}#{passthru_key}#{PASS_END}`)
       end
     else


Test patch:
diff --git a/test/substitutions_test.rb b/test/substitutions_test.rb
index ab0edf104e..91729a7d19 100644
--- a/test/substitutions_test.rb
+++ b/test/substitutions_test.rb
@@ -1937,6 +1937,12 @@
         assert_equal 'the text <code>asciimath:[x = y]</code> should be passed through as <code>literal</code> text', para.content
       end
 
+      test 'should support attrlist on a literal monospace phrase' do
+        input = '[.baz]`+foo--bar+`'
+        para = block_from_string input
+        assert_equal '<code class="baz">foo--bar</code>', para.content
+      end
+
       test 'should not process an escaped passthrough macro inside a monospaced phrase' do
         input = 'use the `\pass:c[]` macro'
         para = block_from_string input