Repository: eslint/doctrine (js)

Issue:
Support type expression for @this tag
Using a name expression with `@this` currently generates an error with "Missing or invalid tag name":

```js
/**
 * @this {Widget}
 */
```

With the closure compiler, a type expression is required after `@this` (see the [annotation docs](https://developers.google.com/closure/compiler/docs/js-for-compiler?hl=en#tag-this)).

The [usejsdoc.org docs](http://usejsdoc.org/tags-this.html) imply that a name path should follow `@this`.  It would be nice to support those using doctrine (or ESLint) with code that uses annotations for the closure compiler (and the `valid-jsdoc` rule).
 

Pull request:
New: support name expression for @this tag (fixes #143)
This adds support for a name in a type expression following `@this` (in addition to the current name path support).

I recognize that this adds more (potentially lightly used) conditions to the supported syntax.  Let me know if you would suggest another way of handling the conditional type parsing.

Fixes #143.

Patch:
diff --git a/lib/doctrine.js b/lib/doctrine.js
index f8330f4..029a63f 100644
--- a/lib/doctrine.js
+++ b/lib/doctrine.js
@@ -582,6 +582,23 @@
             return true;
         };
 
+        TagParser.prototype.parseThis = function parseAccess() {
+            // this name may be a name expression (e.g. {foo.bar})
+            // or a name path (e.g. foo.bar)
+            var value = trim(sliceSource(source, index, this._last));
+            if (value && value.charAt(0) === '{') {
+                var gotType = this.parseType();
+                if (gotType && this._tag.type.type === 'NameExpression') {
+                    this._tag.name = this._tag.type.name;
+                    return true;
+                } else {
+                    return this.addError('Invalid name for this');
+                }
+            } else {
+                return this.parseNamePath();
+            }
+        };
+
         TagParser.prototype.parseVariation = function parseVariation() {
             var variation, text;
             text = trim(sliceSource(source, index, this._last));
@@ -688,7 +705,7 @@
             // http://usejsdoc.org/tags-summary.html
             'summary': ['parseDescription'],
             // http://usejsdoc.org/tags-this.html
-            'this': ['parseNamePath', 'ensureEnd'],
+            'this': ['parseThis', 'ensureEnd'],
             // http://usejsdoc.org/tags-todo.html
             'todo': ['parseDescription'],
             // http://usejsdoc.org/tags-typedef.html


Test patch:
diff --git a/test/parse.js b/test/parse.js
index a282d28..8b51a46 100644
--- a/test/parse.js
+++ b/test/parse.js
@@ -1117,6 +1117,32 @@ describe('parse', function () {
         res.tags[0].should.have.property('name', 'thingName.name');
     });
 
+    it('this with name expression', function () {
+        var res = doctrine.parse(
+            [
+              "/**",
+              " * @this {thingName.name}",
+              "*/"
+            ].join('\n'), { unwrap: true });
+        res.tags.should.have.length(1);
+        res.tags[0].should.have.property('title', 'this');
+        res.tags[0].should.have.property('name', 'thingName.name');
+    });
+
+    it('this error with type application', function () {
+        var res = doctrine.parse(
+            [
+              "/**",
+              " * @this {Array<string>}",
+              "*/"
+            ].join('\n'), { unwrap: true, recoverable: true });
+        res.tags.should.have.length(1);
+        res.tags[0].should.have.property('title', 'this');
+        res.tags[0].should.have.property('errors');
+        res.tags[0].errors.should.have.length(1);
+        res.tags[0].errors[0].should.equal('Invalid name for this');
+    });
+
     it('this error', function () {
         var res = doctrine.parse(
             [