changeset 2344:40f46df6ec3a

Automated merge with http://hg.openjdk.java.net/type-annotations/type-annotations/langtools
author wmdietl
date Wed, 20 Mar 2013 18:42:11 +0100
parents 8d0997a404a6 5d8736d4de0b
children 356feec37282
files src/share/classes/com/sun/tools/javac/code/Printer.java src/share/classes/com/sun/tools/javac/code/Type.java src/share/classes/com/sun/tools/javac/code/Types.java src/share/classes/com/sun/tools/javac/comp/Attr.java
diffstat 14 files changed, 197 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/code/Printer.java	Mon Mar 18 19:28:29 2013 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Printer.java	Wed Mar 20 18:42:11 2013 +0100
@@ -31,6 +31,7 @@
 
 import com.sun.tools.javac.api.Messages;
 import com.sun.tools.javac.code.Type.AnnotatedType;
+import com.sun.tools.javac.code.Type.ArrayType;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.util.List;
@@ -127,7 +128,7 @@
     }
 
     /**
-     * Get a localized string represenation for a given type.
+     * Get a localized string representation for a given type.
      *
      * @param t type to be displayed
      * @param locale the locale in which the string is to be rendered
@@ -138,7 +139,7 @@
     }
 
     /**
-     * Get a localized string represenation for a given symbol.
+     * Get a localized string representation for a given symbol.
      *
      * @param s symbol to be displayed
      * @param locale the locale in which the string is to be rendered
@@ -182,7 +183,33 @@
 
     @Override
     public String visitArrayType(ArrayType t, Locale locale) {
-        return visit(t.elemtype, locale) + "[]";
+        StringBuilder res = new StringBuilder();
+        printBaseElementType(t, res, locale);
+        printBrackets(t, res, locale);
+        return res.toString();
+    }
+
+    void printBaseElementType(Type t, StringBuilder sb, Locale locale) {
+        Type arrel = t;
+        while (arrel.getKind() == TypeKind.ARRAY) {
+            arrel = arrel.unannotatedType();
+            arrel = ((ArrayType) arrel).elemtype;
+        }
+        sb.append(visit(arrel, locale));
+    }
+
+    void printBrackets(Type t, StringBuilder sb, Locale locale) {
+        Type arrel = t;
+        while (arrel.getKind() == TypeKind.ARRAY) {
+            if (arrel.isAnnotated()) {
+                sb.append(' ');
+                sb.append(arrel.getAnnotationMirrors());
+                sb.append(' ');
+            }
+            sb.append("[]");
+            arrel = arrel.unannotatedType();
+            arrel = ((ArrayType) arrel).elemtype;
+        }
     }
 
     @Override
@@ -237,10 +264,24 @@
     public String visitAnnotatedType(AnnotatedType t, Locale locale) {
         if (t.typeAnnotations != null &&
                 t.typeAnnotations.nonEmpty()) {
-            // TODO: better logic for arrays, ...
-            return "(" + t.typeAnnotations + " :: " + visit(t.underlyingType, locale) + ")";
+            if (t.underlyingType.getKind() == TypeKind.ARRAY) {
+                StringBuilder res = new StringBuilder();
+                printBaseElementType(t, res, locale);
+                printBrackets(t, res, locale);
+                return res.toString();
+            } else if (t.underlyingType.getKind() == TypeKind.DECLARED &&
+                    t.underlyingType.getEnclosingType() != Type.noType) {
+                return visit(t.underlyingType.getEnclosingType(), locale) +
+                        ". " +
+                        t.typeAnnotations +
+                        " " + t.underlyingType;
+            } else {
+                // TODO: this prints "@A java.lang.Object". How can we easily
+                // split of the package name? Nested types are handled above.
+                return t.typeAnnotations + " " + visit(t.underlyingType, locale);
+            }
         } else {
-            return "({} :: " + visit(t.underlyingType, locale) + ")";
+            return visit(t.underlyingType, locale);
         }
     }
 
@@ -253,7 +294,7 @@
 
     /**
      * Converts a class name into a (possibly localized) string. Anonymous
-     * inner classes gets converted into a localized string.
+     * inner classes get converted into a localized string.
      *
      * @param t the type of the class whose name is to be rendered
      * @param longform if set, the class' fullname is displayed - if unset the
@@ -266,7 +307,7 @@
         if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) {
             StringBuilder s = new StringBuilder(visit(t.supertype_field, locale));
             for (List<Type> is = t.interfaces_field; is.nonEmpty(); is = is.tail) {
-                s.append("&");
+                s.append('&');
                 s.append(visit(is.head, locale));
             }
             return s.toString();
--- a/src/share/classes/com/sun/tools/javac/code/Type.java	Mon Mar 18 19:28:29 2013 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Type.java	Wed Mar 20 18:42:11 2013 +0100
@@ -1686,7 +1686,10 @@
 
         @Override
         public String toString() {
-            // TODO more logic for arrays, etc.
+            // This method is only used for internal debugging output.
+            // See
+            // com.sun.tools.javac.code.Printer.visitAnnotatedType(AnnotatedType, Locale)
+            // for the user-visible logic.
             if (typeAnnotations != null &&
                     !typeAnnotations.isEmpty()) {
                 return "(" + typeAnnotations.toString() + " :: " + underlyingType.toString() + ")";
@@ -1698,9 +1701,13 @@
         @Override
         public boolean contains(Type t)          { return underlyingType.contains(t); }
 
-        // TODO: attach annotations?
         @Override
-        public Type withTypeVar(Type t)          { return underlyingType.withTypeVar(t); }
+        public Type withTypeVar(Type t) {
+            // Don't create a new AnnotatedType, as 'this' will
+            // get its annotations set later.
+            underlyingType = underlyingType.withTypeVar(t);
+            return this;
+        }
 
         // TODO: attach annotations?
         @Override
--- a/src/share/classes/com/sun/tools/javac/code/Types.java	Mon Mar 18 19:28:29 2013 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Types.java	Wed Mar 20 18:42:11 2013 +0100
@@ -1037,7 +1037,7 @@
                     if (s.tag == TYPEVAR) {
                         //type-substitution does not preserve type-var types
                         //check that type var symbols and bounds are indeed the same
-                        return sameTypeVars((TypeVar)t, (TypeVar)s);
+                        return sameTypeVars((TypeVar)t.unannotatedType(), (TypeVar)s.unannotatedType());
                     }
                     else {
                         //special case for s == ? super X, where upper(s) = u
@@ -3755,9 +3755,9 @@
                !currentS.isEmpty()) {
             if (currentS.head != currentT.head) {
                 captured = true;
-                WildcardType Ti = (WildcardType)currentT.head;
+                WildcardType Ti = (WildcardType)currentT.head.unannotatedType();
                 Type Ui = currentA.head.getUpperBound();
-                CapturedType Si = (CapturedType)currentS.head;
+                CapturedType Si = (CapturedType)currentS.head.unannotatedType();
                 if (Ui == null)
                     Ui = syms.objectType;
                 switch (Ti.kind) {
@@ -3794,6 +3794,7 @@
             ListBuffer<Type> result = lb();
             for (Type t : types) {
                 if (t.tag == WILDCARD) {
+                    t = t.unannotatedType();
                     Type bound = ((WildcardType)t).getExtendsBound();
                     if (bound == null)
                         bound = syms.objectType;
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Mar 18 19:28:29 2013 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Mar 20 18:42:11 2013 +0100
@@ -938,10 +938,31 @@
                 Env<AttrContext> newEnv = memberEnter.methodEnv(tree, env);
                 attribType(tree.recvparam, newEnv);
                 chk.validate(tree.recvparam, newEnv);
-                if (!(tree.recvparam.type == m.owner.type || types.isSameType(tree.recvparam.type, m.owner.type))) {
+                if (tree.name == names.init) {
+                    // In a constructor
+                    Type outertype = m.owner.owner.type;
+                    Type recvtype = tree.recvparam.type;
+                    if (outertype.getKind() != TypeKind.DECLARED) {
+                        // e.g. PACKAGE for top-level class
+                        log.error(tree.recvparam.pos(), "receiver.parameter.not.applicable.constructor.toplevel.class", tree.recvparam);
+                    }
+                    if (!(recvtype == outertype || types.isSameType(recvtype, outertype))) {
+                        // The == covers the common non-generic case, but for generic classes we need isSameType;
+                        // note that equals didn't work.
+                        log.error(tree.recvparam.pos(), "incorrect.constructor.receiver.type", outertype, recvtype);
+                    }
+                    {
+                        // Make sure the receiver parameter name is as expected
+                        String fnd = tree.recvparam.nameexpr.toString();
+                        String exp = recvtype.unannotatedType().toString() + '.' + names._this.toString();
+                        if (!exp.endsWith(fnd)) {
+                            log.error(tree.recvparam.pos(), "receiver.parameter.wrong.name", exp, fnd);
+                        }
+                    }
+                } else if (!(tree.recvparam.type == m.owner.type || types.isSameType(tree.recvparam.type, m.owner.type))) {
                     // The == covers the common non-generic case, but for generic classes we need isSameType;
                     // note that equals didn't work.
-                    log.error(tree.recvparam.pos(), "incorrect.receiver.type");
+                    log.error(tree.recvparam.pos(), "incorrect.receiver.type", m.owner.type, tree.recvparam.type);
                 }
             }
 
@@ -3738,6 +3759,12 @@
                     }
                 }
                 owntype = new ClassType(clazzOuter, actuals, clazztype.tsym);
+                if (clazztype.isAnnotated()) {
+                    // Use the same AnnotatedType, because it will have
+                    // its annotations set later.
+                    ((AnnotatedType)clazztype).underlyingType = owntype;
+                    owntype = clazztype;
+                }
             } else {
                 if (formals.length() != 0) {
                     log.error(tree.pos(), "wrong.number.type.args",
@@ -4274,7 +4301,7 @@
             // I would say it's safe to skip.
             if (tree.sym != null && (tree.sym.flags() & Flags.STATIC) != 0) {
                 if (tree.recvparam != null) {
-                    log.error(tree.recvparam.pos(), "receiver.parameter.not.applicable");
+                    log.error(tree.recvparam.pos(), "receiver.parameter.not.applicable.static", tree.recvparam);
                 }
             }
             if (tree.recvparam != null &&
--- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Mon Mar 18 19:28:29 2013 -0700
+++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Wed Mar 20 18:42:11 2013 +0100
@@ -262,7 +262,7 @@
 
     /** The type of the method receiver, as specified by a first "this" parameter.
      */
-    JCVariableDecl receiverParam;
+    JCReceiverVariableDecl receiverParam;
 
 
     /** When terms are parsed, the mode determines which is expected:
@@ -2997,7 +2997,22 @@
             syntaxError(pos, "expected", IDENTIFIER);
             name = token.name();
         } else {
-            name = ident();
+            if (allowThisIdent) {
+                JCExpression pn = qualident(false);
+                if (pn.hasTag(Tag.IDENT) && !((JCIdent)pn).name.contentEquals(TokenKind.THIS.name)) {
+                    name = ((JCIdent)pn).name;
+                } else {
+                    if ((mods.flags & Flags.VARARGS) != 0) {
+                        log.error(token.pos, "varargs.and.receiver");
+                    }
+                    if (token.kind == LBRACKET) {
+                        log.error(token.pos, "array.and.receiver");
+                    }
+                    return toP(F.at(pos).ReceiverVarDef(mods, pn, type));
+                }
+            } else {
+                name = ident();
+            }
         }
         if ((mods.flags & Flags.VARARGS) != 0 &&
                 token.kind == LBRACKET) {
@@ -3485,7 +3500,7 @@
         if (isInterface && (mods.flags & Flags.STATIC) != 0) {
             checkStaticInterfaceMethods();
         }
-        JCVariableDecl prevReceiverParam = this.receiverParam;
+        JCReceiverVariableDecl prevReceiverParam = this.receiverParam;
         try {
             this.receiverParam = null;
             // Parsing formalParameters sets the receiverParam, if present
@@ -3610,8 +3625,8 @@
         if (token.kind != RPAREN) {
             this.allowThisIdent = true;
             lastParam = formalParameter(lambdaParameters);
-            if (lastParam.name.contentEquals(TokenKind.THIS.name)) {
-                this.receiverParam = lastParam;
+            if (lastParam instanceof JCReceiverVariableDecl) {
+                this.receiverParam = (JCReceiverVariableDecl) lastParam;
             } else {
                 params.append(lastParam);
             }
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon Mar 18 19:28:29 2013 -0700
+++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Mar 20 18:42:11 2013 +0100
@@ -2176,8 +2176,11 @@
     as of release 8, ''this'' is allowed as the parameter name for the receiver type only, which has to be the first parameter
 
 # TODO 308: make a better error message
-compiler.err.receiver.parameter.not.applicable=\
-    receiver parameter not applicable
+compiler.err.receiver.parameter.not.applicable.static=\
+    receiver parameter not applicable for static method: {0}
+
+compiler.err.receiver.parameter.not.applicable.constructor.toplevel.class=\
+    receiver parameter not applicable for constructor of top-level class: {0}
 
 # TODO 308: make a better error message
 compiler.err.cant.annotate.static.class=\
@@ -2187,7 +2190,19 @@
     nested type cannot be annotated
 
 compiler.err.incorrect.receiver.type=\
-    the receiver type does not match the enclosing class type
+    the receiver type does not match the enclosing class type\n\
+    required: {0}\n\
+    found: {1}
+
+compiler.err.incorrect.constructor.receiver.type=\
+    the receiver type does not match the enclosing outer class type\n\
+    required: {0}\n\
+    found: {1}
+
+compiler.err.receiver.parameter.wrong.name=\
+    the receiver parameter has a wrong name\n\
+    required: {0}\n\
+    found: {1}
 
 compiler.err.no.annotations.on.dot.class=\
     no annotations are allowed in the type of a class literal
--- a/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Mon Mar 18 19:28:29 2013 -0700
+++ b/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Wed Mar 20 18:42:11 2013 +0100
@@ -42,7 +42,6 @@
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 import com.sun.tools.javac.util.List;
-import static com.sun.tools.javac.code.BoundKind.*;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
 
 /**
@@ -732,7 +731,7 @@
         /** type parameters */
         public List<JCTypeParameter> typarams;
         /** receiver parameter */
-        public JCVariableDecl recvparam;
+        public JCReceiverVariableDecl recvparam;
         /** value parameters */
         public List<JCVariableDecl> params;
         /** exceptions thrown by this method */
@@ -747,7 +746,7 @@
                             Name name,
                             JCExpression restype,
                             List<JCTypeParameter> typarams,
-                            JCVariableDecl recvparam,
+                            JCReceiverVariableDecl recvparam,
                             List<JCVariableDecl> params,
                             List<JCExpression> thrown,
                             JCBlock body,
@@ -780,7 +779,7 @@
         public List<JCVariableDecl> getParameters() {
             return params;
         }
-        public JCVariableDecl getReceiverParameter() { return recvparam; }
+        public JCReceiverVariableDecl getReceiverParameter() { return recvparam; }
         public List<JCExpression> getThrows() {
             return thrown;
         }
@@ -845,7 +844,30 @@
         }
     }
 
-      /**
+    /**
+     * A receiver variable declaration:
+     *   C this
+     *   Outer Outer.this
+     */
+    public static class JCReceiverVariableDecl extends JCVariableDecl {
+        /** variable name expression */
+        public JCExpression nameexpr;
+        protected JCReceiverVariableDecl(JCModifiers mods,
+                         JCExpression nameexpr,
+                         JCExpression vartype) {
+            super(mods, null, vartype, null, null);
+            this.nameexpr = nameexpr;
+            if (nameexpr.hasTag(Tag.IDENT)) {
+                this.name = ((JCIdent)nameexpr).name;
+            } else {
+                // Only other option is qualified name x.y.this;
+                this.name = ((JCFieldAccess)nameexpr).name;
+            }
+        }
+        // TODO: do we want a separate tag?
+    }
+
+    /**
      * A no-op statement ";".
      */
     public static class JCSkip extends JCStatement implements EmptyStatementTree {
@@ -2413,7 +2435,7 @@
                             Name name,
                             JCExpression restype,
                             List<JCTypeParameter> typarams,
-                            JCVariableDecl recvparam,
+                            JCReceiverVariableDecl recvparam,
                             List<JCVariableDecl> params,
                             List<JCExpression> thrown,
                             JCBlock body,
--- a/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Mon Mar 18 19:28:29 2013 -0700
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Wed Mar 20 18:42:11 2013 +0100
@@ -248,7 +248,7 @@
         JCExpression restype = copy(t.restype, p);
         List<JCTypeParameter> typarams = copy(t.typarams, p);
         List<JCVariableDecl> params = copy(t.params, p);
-        JCVariableDecl recvparam = copy(t.recvparam, p);
+        JCReceiverVariableDecl recvparam = copy(t.recvparam, p);
         List<JCExpression> thrown = copy(t.thrown, p);
         JCBlock body = copy(t.body, p);
         JCExpression defaultValue = copy(t.defaultValue, p);
--- a/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Mon Mar 18 19:28:29 2013 -0700
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Wed Mar 20 18:42:11 2013 +0100
@@ -178,7 +178,7 @@
                                Name name,
                                JCExpression restype,
                                List<JCTypeParameter> typarams,
-                               JCVariableDecl recvparam,
+                               JCReceiverVariableDecl recvparam,
                                List<JCVariableDecl> params,
                                List<JCExpression> thrown,
                                JCBlock body,
@@ -204,6 +204,12 @@
         return tree;
     }
 
+    public JCReceiverVariableDecl ReceiverVarDef(JCModifiers mods, JCExpression name, JCExpression vartype) {
+        JCReceiverVariableDecl tree = new JCReceiverVariableDecl(mods, name, vartype);
+        tree.pos = pos;
+        return tree;
+    }
+
     public JCSkip Skip() {
         JCSkip tree = new JCSkip();
         tree.pos = pos;
--- a/test/tools/javac/annotations/typeAnnotations/failures/LintCast.out	Mon Mar 18 19:28:29 2013 -0700
+++ b/test/tools/javac/annotations/typeAnnotations/failures/LintCast.out	Wed Mar 20 18:42:11 2013 +0100
@@ -1,11 +1,11 @@
 LintCast.java:15:21: compiler.warn.redundant.cast: java.lang.String
 LintCast.java:21:27: compiler.warn.redundant.cast: java.util.List<java.lang.String>
-LintCast.java:27:20: compiler.warn.redundant.cast: (@A :: int[])
+LintCast.java:27:20: compiler.warn.redundant.cast: int @A []
 LintCast.java:39:24: compiler.warn.redundant.cast: java.lang.String
 LintCast.java:40:26: compiler.warn.redundant.cast: java.lang.String
-LintCast.java:45:23: compiler.warn.redundant.cast: (@A :: java.lang.Object[])
+LintCast.java:45:23: compiler.warn.redundant.cast: java.lang.Object @A []
 LintCast.java:49:27: compiler.warn.redundant.cast: java.util.List<java.lang.String>
-LintCast.java:53:27: compiler.warn.redundant.cast: java.util.List<java.lang.String>
+LintCast.java:53:27: compiler.warn.redundant.cast: java.util.List<@A java.lang.String>
 LintCast.java:57:21: compiler.warn.redundant.cast: java.lang.Object
 LintCast.java:61:27: compiler.warn.redundant.cast: LintCast.Outer.Inner
 10 warnings
\ No newline at end of file
--- a/test/tools/javac/annotations/typeAnnotations/failures/StaticMethods.out	Mon Mar 18 19:28:29 2013 -0700
+++ b/test/tools/javac/annotations/typeAnnotations/failures/StaticMethods.out	Wed Mar 20 18:42:11 2013 +0100
@@ -1,2 +1,2 @@
-StaticMethods.java:9:34: compiler.err.receiver.parameter.not.applicable
+StaticMethods.java:9:34: compiler.err.receiver.parameter.not.applicable.static: StaticMethods this
 1 error
\ No newline at end of file
--- a/test/tools/javac/annotations/typeAnnotations/failures/common/receiver/StaticThings.out	Mon Mar 18 19:28:29 2013 -0700
+++ b/test/tools/javac/annotations/typeAnnotations/failures/common/receiver/StaticThings.out	Wed Mar 20 18:42:11 2013 +0100
@@ -1,5 +1,5 @@
-StaticThings.java:52:32: compiler.err.receiver.parameter.not.applicable
-StaticThings.java:54:37: compiler.err.receiver.parameter.not.applicable
-StaticThings.java:33:26: compiler.err.receiver.parameter.not.applicable
-StaticThings.java:36:28: compiler.err.receiver.parameter.not.applicable
+StaticThings.java:52:32: compiler.err.receiver.parameter.not.applicable.static: Nested2 this
+StaticThings.java:54:37: compiler.err.receiver.parameter.not.applicable.static: Test.Nested2 this
+StaticThings.java:33:26: compiler.err.receiver.parameter.not.applicable.static: Test this
+StaticThings.java:36:28: compiler.err.receiver.parameter.not.applicable.static: Test this
 4 errors
\ No newline at end of file
--- a/test/tools/javac/annotations/typeAnnotations/failures/common/receiver/WrongType.out	Mon Mar 18 19:28:29 2013 -0700
+++ b/test/tools/javac/annotations/typeAnnotations/failures/common/receiver/WrongType.out	Wed Mar 20 18:42:11 2013 +0100
@@ -1,9 +1,9 @@
 WrongType.java:55:15: compiler.err.cant.resolve.location: kindname.class, XYZ, , , (compiler.misc.location: kindname.class, WrongType, null)
 WrongType.java:65:27: compiler.err.doesnt.exist: Outer
 WrongType.java:66:31: compiler.err.cant.resolve.location: kindname.class, XY, , , (compiler.misc.location: kindname.class, WrongType, null)
-WrongType.java:48:23: compiler.err.incorrect.receiver.type
-WrongType.java:50:23: compiler.err.incorrect.receiver.type
-WrongType.java:63:33: compiler.err.incorrect.receiver.type
-WrongType.java:64:31: compiler.err.incorrect.receiver.type
-WrongType.java:70:28: compiler.err.incorrect.receiver.type
+WrongType.java:48:23: compiler.err.incorrect.receiver.type: WrongType, @A java.lang.Object
+WrongType.java:50:23: compiler.err.incorrect.receiver.type: WrongType, @A java.lang.Object
+WrongType.java:63:33: compiler.err.incorrect.receiver.type: WrongType.Inner, @A WrongType
+WrongType.java:64:31: compiler.err.incorrect.receiver.type: WrongType.Inner, @A java.lang.Object
+WrongType.java:70:28: compiler.err.incorrect.receiver.type: WrongType.Generics<X>, WrongType.Generics<Y>
 8 errors
\ No newline at end of file
--- a/test/tools/javac/annotations/typeAnnotations/referenceinfos/Constructors.java	Mon Mar 18 19:28:29 2013 -0700
+++ b/test/tools/javac/annotations/typeAnnotations/referenceinfos/Constructors.java	Wed Mar 20 18:42:11 2013 +0100
@@ -54,7 +54,6 @@
                " } }";
     }
 
-    /* TODO: Outer.this annotation support.
     @TADescriptions({
         @TADescription(annotation = "TA", type = METHOD_RECEIVER),
         @TADescription(annotation = "TB", type = METHOD_RETURN),
@@ -69,5 +68,21 @@
                " @TD Inner(@TC Test Test.this, @TE int b) {}" +
                " } }";
     }
-    */
+
+    @TADescriptions({
+        @TADescription(annotation = "TA", type = METHOD_RECEIVER),
+        @TADescription(annotation = "TB", type = METHOD_RECEIVER, genericLocation = {1, 0}),
+        @TADescription(annotation = "TC", type = METHOD_RETURN),
+        @TADescription(annotation = "TD", type = METHOD_RECEIVER, genericLocation = {1, 0}),
+        @TADescription(annotation = "TE", type = METHOD_RETURN),
+        @TADescription(annotation = "TF", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
+    })
+    @TestClass("Outer$Middle$Inner")
+    public String innerClass3() {
+        return "class Outer { class Middle { class Inner {" +
+               " @TC Inner(@TA Outer. @TB Middle Middle.this) {}" +
+               " @TE Inner(@TD Middle Outer.Middle.this, @TF int b) {}" +
+               " } } }";
+    }
+
 }