7030687: Diamond: compiler accepts erroneous code where diamond is used with non-generic inner class

Tue, 29 Mar 2011 16:40:07 +0100

author
mcimadamore
date
Tue, 29 Mar 2011 16:40:07 +0100
changeset 948
2007998f89f2
parent 947
442b1366cfdf
child 949
ddec8c712e85

7030687: Diamond: compiler accepts erroneous code where diamond is used with non-generic inner class
Summary: Diamond accepts non-parameterized member inner classes with parameterized outer because of a bad check
Reviewed-by: jjg

src/share/classes/com/sun/tools/javac/comp/Check.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/parser/JavacParser.java file | annotate | diff | comparison | revisions
test/tools/javac/generics/diamond/7030687/ParserTest.java file | annotate | diff | comparison | revisions
test/tools/javac/generics/diamond/7030687/T7030687.java file | annotate | diff | comparison | revisions
test/tools/javac/generics/diamond/7030687/T7030687.out file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Check.java	Fri Mar 25 15:17:52 2011 -0700
     1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Check.java	Tue Mar 29 16:40:07 2011 +0100
     1.3 @@ -676,7 +676,7 @@
     1.4                      "cant.apply.diamond.1",
     1.5                      t, diags.fragment("diamond.and.anon.class", t));
     1.6              return types.createErrorType(t);
     1.7 -        } else if (!t.tsym.type.isParameterized()) {
     1.8 +        } else if (t.tsym.type.getTypeArguments().isEmpty()) {
     1.9              log.error(tree.clazz.pos(),
    1.10                  "cant.apply.diamond.1",
    1.11                  t, diags.fragment("diamond.non.generic", t));
     2.1 --- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Mar 25 15:17:52 2011 -0700
     2.2 +++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Tue Mar 29 16:40:07 2011 +0100
     2.3 @@ -971,7 +971,7 @@
     2.4              if ((mode & EXPR) != 0) {
     2.5                  mode = EXPR;
     2.6                  S.nextToken();
     2.7 -                if (S.token() == LT) typeArgs = typeArguments();
     2.8 +                if (S.token() == LT) typeArgs = typeArguments(false);
     2.9                  t = creator(pos, typeArgs);
    2.10                  typeArgs = null;
    2.11              } else return illegal();
    2.12 @@ -1036,7 +1036,7 @@
    2.13                              mode = EXPR;
    2.14                              int pos1 = S.pos();
    2.15                              S.nextToken();
    2.16 -                            if (S.token() == LT) typeArgs = typeArguments();
    2.17 +                            if (S.token() == LT) typeArgs = typeArguments(false);
    2.18                              t = innerCreator(pos1, typeArgs, t);
    2.19                              typeArgs = null;
    2.20                              break loop;
    2.21 @@ -1116,7 +1116,7 @@
    2.22                      mode = EXPR;
    2.23                      int pos2 = S.pos();
    2.24                      S.nextToken();
    2.25 -                    if (S.token() == LT) typeArgs = typeArguments();
    2.26 +                    if (S.token() == LT) typeArgs = typeArguments(false);
    2.27                      t = innerCreator(pos2, typeArgs, t);
    2.28                      typeArgs = null;
    2.29                  } else {
    2.30 @@ -1146,7 +1146,7 @@
    2.31          } else {
    2.32              int pos = S.pos();
    2.33              accept(DOT);
    2.34 -            typeArgs = (S.token() == LT) ? typeArguments() : null;
    2.35 +            typeArgs = (S.token() == LT) ? typeArguments(false) : null;
    2.36              t = toP(F.at(pos).Select(t, ident()));
    2.37              t = argumentsOpt(typeArgs, t);
    2.38          }
    2.39 @@ -1206,7 +1206,7 @@
    2.40              (mode & NOPARAMS) == 0) {
    2.41              mode = TYPE;
    2.42              checkGenerics();
    2.43 -            return typeArguments(t);
    2.44 +            return typeArguments(t, false);
    2.45          } else {
    2.46              return t;
    2.47          }
    2.48 @@ -1223,51 +1223,54 @@
    2.49                  illegal();
    2.50              }
    2.51              mode = useMode;
    2.52 -            return typeArguments();
    2.53 +            return typeArguments(false);
    2.54          }
    2.55          return null;
    2.56      }
    2.57  
    2.58      /**  TypeArguments  = "<" TypeArgument {"," TypeArgument} ">"
    2.59       */
    2.60 -    List<JCExpression> typeArguments() {
    2.61 -        ListBuffer<JCExpression> args = lb();
    2.62 +    List<JCExpression> typeArguments(boolean diamondAllowed) {
    2.63          if (S.token() == LT) {
    2.64              S.nextToken();
    2.65 -            if (S.token() == GT && (mode & DIAMOND) != 0) {
    2.66 +            if (S.token() == GT && diamondAllowed) {
    2.67                  checkDiamond();
    2.68 +                mode |= DIAMOND;
    2.69                  S.nextToken();
    2.70                  return List.nil();
    2.71 -            }
    2.72 -            args.append(((mode & EXPR) == 0) ? typeArgument() : parseType());
    2.73 -            while (S.token() == COMMA) {
    2.74 -                S.nextToken();
    2.75 +            } else {
    2.76 +                ListBuffer<JCExpression> args = ListBuffer.lb();
    2.77                  args.append(((mode & EXPR) == 0) ? typeArgument() : parseType());
    2.78 -            }
    2.79 -            switch (S.token()) {
    2.80 -            case GTGTGTEQ:
    2.81 -                S.token(GTGTEQ);
    2.82 -                break;
    2.83 -            case GTGTEQ:
    2.84 -                S.token(GTEQ);
    2.85 -                break;
    2.86 -            case GTEQ:
    2.87 -                S.token(EQ);
    2.88 -                break;
    2.89 -            case GTGTGT:
    2.90 -                S.token(GTGT);
    2.91 -                break;
    2.92 -            case GTGT:
    2.93 -                S.token(GT);
    2.94 -                break;
    2.95 -            default:
    2.96 -                accept(GT);
    2.97 -                break;
    2.98 +                while (S.token() == COMMA) {
    2.99 +                    S.nextToken();
   2.100 +                    args.append(((mode & EXPR) == 0) ? typeArgument() : parseType());
   2.101 +                }
   2.102 +                switch (S.token()) {
   2.103 +                case GTGTGTEQ:
   2.104 +                    S.token(GTGTEQ);
   2.105 +                    break;
   2.106 +                case GTGTEQ:
   2.107 +                    S.token(GTEQ);
   2.108 +                    break;
   2.109 +                case GTEQ:
   2.110 +                    S.token(EQ);
   2.111 +                    break;
   2.112 +                case GTGTGT:
   2.113 +                    S.token(GTGT);
   2.114 +                    break;
   2.115 +                case GTGT:
   2.116 +                    S.token(GT);
   2.117 +                    break;
   2.118 +                default:
   2.119 +                    accept(GT);
   2.120 +                    break;
   2.121 +                }
   2.122 +                return args.toList();
   2.123              }
   2.124          } else {
   2.125              syntaxError(S.pos(), "expected", LT);
   2.126 +            return List.nil();
   2.127          }
   2.128 -        return args.toList();
   2.129      }
   2.130  
   2.131      /** TypeArgument = Type
   2.132 @@ -1303,9 +1306,9 @@
   2.133          }
   2.134      }
   2.135  
   2.136 -    JCTypeApply typeArguments(JCExpression t) {
   2.137 +    JCTypeApply typeArguments(JCExpression t, boolean diamondAllowed) {
   2.138          int pos = S.pos();
   2.139 -        List<JCExpression> args = typeArguments();
   2.140 +        List<JCExpression> args = typeArguments(diamondAllowed);
   2.141          return toP(F.at(pos).TypeApply(t, args));
   2.142      }
   2.143  
   2.144 @@ -1370,18 +1373,25 @@
   2.145          }
   2.146          JCExpression t = qualident();
   2.147          int oldmode = mode;
   2.148 -        mode = TYPE | DIAMOND;
   2.149 +        mode = TYPE;
   2.150 +        boolean diamondFound = false;
   2.151          if (S.token() == LT) {
   2.152              checkGenerics();
   2.153 -            t = typeArguments(t);
   2.154 +            t = typeArguments(t, true);
   2.155 +            diamondFound = (mode & DIAMOND) != 0;
   2.156          }
   2.157          while (S.token() == DOT) {
   2.158 +            if (diamondFound) {
   2.159 +                //cannot select after a diamond
   2.160 +                illegal(S.pos());
   2.161 +            }
   2.162              int pos = S.pos();
   2.163              S.nextToken();
   2.164              t = toP(F.at(pos).Select(t, ident()));
   2.165              if (S.token() == LT) {
   2.166                  checkGenerics();
   2.167 -                t = typeArguments(t);
   2.168 +                t = typeArguments(t, true);
   2.169 +                diamondFound = (mode & DIAMOND) != 0;
   2.170              }
   2.171          }
   2.172          mode = oldmode;
   2.173 @@ -1416,9 +1426,8 @@
   2.174          JCExpression t = toP(F.at(S.pos()).Ident(ident()));
   2.175          if (S.token() == LT) {
   2.176              int oldmode = mode;
   2.177 -            mode |= DIAMOND;
   2.178              checkGenerics();
   2.179 -            t = typeArguments(t);
   2.180 +            t = typeArguments(t, true);
   2.181              mode = oldmode;
   2.182          }
   2.183          return classCreatorRest(newpos, encl, typeArgs, t);
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/test/tools/javac/generics/diamond/7030687/ParserTest.java	Tue Mar 29 16:40:07 2011 +0100
     3.3 @@ -0,0 +1,175 @@
     3.4 +/*
     3.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
     3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3.7 + *
     3.8 + * This code is free software; you can redistribute it and/or modify it
     3.9 + * under the terms of the GNU General Public License version 2 only, as
    3.10 + * published by the Free Software Foundation.
    3.11 + *
    3.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    3.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    3.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    3.15 + * version 2 for more details (a copy is included in the LICENSE file that
    3.16 + * accompanied this code).
    3.17 + *
    3.18 + * You should have received a copy of the GNU General Public License version
    3.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    3.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    3.21 + *
    3.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    3.23 + * or visit www.oracle.com if you need additional information or have any
    3.24 + * questions.
    3.25 + */
    3.26 +
    3.27 +/*
    3.28 + * @test
    3.29 + * @bug 7030687
    3.30 + * @summary Diamond: compiler accepts erroneous code where diamond is used with non-generic inner class
    3.31 + */
    3.32 +
    3.33 +import com.sun.source.util.JavacTask;
    3.34 +import java.net.URI;
    3.35 +import java.util.Arrays;
    3.36 +import javax.tools.Diagnostic;
    3.37 +import javax.tools.JavaCompiler;
    3.38 +import javax.tools.JavaFileObject;
    3.39 +import javax.tools.SimpleJavaFileObject;
    3.40 +import javax.tools.StandardJavaFileManager;
    3.41 +import javax.tools.ToolProvider;
    3.42 +
    3.43 +public class ParserTest {
    3.44 +
    3.45 +    enum TypeArgumentKind {
    3.46 +        NONE(""),
    3.47 +        EXPLICIT("<String>"),
    3.48 +        DIAMOND("<>");
    3.49 +
    3.50 +        String typeargStr;
    3.51 +
    3.52 +        private TypeArgumentKind(String typeargStr) {
    3.53 +            this.typeargStr = typeargStr;
    3.54 +        }
    3.55 +    }
    3.56 +
    3.57 +    enum TypeQualifierArity {
    3.58 +        ONE(1, "A1#TA1"),
    3.59 +        TWO(2, "A1#TA1.A2#TA2"),
    3.60 +        THREE(3, "A1#TA1.A2#TA2.A3#TA3"),
    3.61 +        FOUR(4, "A1#TA1.A2#TA2.A3#TA3.A4#TA4");
    3.62 +
    3.63 +        int n;
    3.64 +        String qualifierStr;
    3.65 +
    3.66 +        private TypeQualifierArity(int n, String qualifierStr) {
    3.67 +            this.n = n;
    3.68 +            this.qualifierStr = qualifierStr;
    3.69 +        }
    3.70 +
    3.71 +        String getType(TypeArgumentKind... typeArgumentKinds) {
    3.72 +            String res = qualifierStr;
    3.73 +            for (int i = 1 ; i <= typeArgumentKinds.length ; i++) {
    3.74 +                res = res.replace("#TA" + i, typeArgumentKinds[i-1].typeargStr);
    3.75 +            }
    3.76 +            return res;
    3.77 +        }
    3.78 +    }
    3.79 +
    3.80 +    public static void main(String... args) throws Exception {
    3.81 +
    3.82 +        //create default shared JavaCompiler - reused across multiple compilations
    3.83 +        JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
    3.84 +        StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
    3.85 +
    3.86 +        for (TypeQualifierArity arity : TypeQualifierArity.values()) {
    3.87 +            for (TypeArgumentKind tak1 : TypeArgumentKind.values()) {
    3.88 +                if (arity == TypeQualifierArity.ONE) {
    3.89 +                    new ParserTest(arity, tak1).run(comp, fm);
    3.90 +                    continue;
    3.91 +                }
    3.92 +                for (TypeArgumentKind tak2 : TypeArgumentKind.values()) {
    3.93 +                    if (arity == TypeQualifierArity.TWO) {
    3.94 +                        new ParserTest(arity, tak1, tak2).run(comp, fm);
    3.95 +                        continue;
    3.96 +                    }
    3.97 +                    for (TypeArgumentKind tak3 : TypeArgumentKind.values()) {
    3.98 +                        if (arity == TypeQualifierArity.THREE) {
    3.99 +                            new ParserTest(arity, tak1, tak2, tak3).run(comp, fm);
   3.100 +                            continue;
   3.101 +                        }
   3.102 +                        for (TypeArgumentKind tak4 : TypeArgumentKind.values()) {
   3.103 +                            new ParserTest(arity, tak1, tak2, tak3, tak4).run(comp, fm);
   3.104 +                        }
   3.105 +                    }
   3.106 +                }
   3.107 +            }
   3.108 +        }
   3.109 +    }
   3.110 +
   3.111 +    TypeQualifierArity qualifierArity;
   3.112 +    TypeArgumentKind[] typeArgumentKinds;
   3.113 +    JavaSource source;
   3.114 +    DiagnosticChecker diagChecker;
   3.115 +
   3.116 +    ParserTest(TypeQualifierArity qualifierArity, TypeArgumentKind... typeArgumentKinds) {
   3.117 +        this.qualifierArity = qualifierArity;
   3.118 +        this.typeArgumentKinds = typeArgumentKinds;
   3.119 +        this.source = new JavaSource();
   3.120 +        this.diagChecker = new DiagnosticChecker();
   3.121 +    }
   3.122 +
   3.123 +    class JavaSource extends SimpleJavaFileObject {
   3.124 +
   3.125 +        String template = "class Test {\n" +
   3.126 +                              "R res = new #T();\n" +
   3.127 +                          "}\n";
   3.128 +
   3.129 +        String source;
   3.130 +
   3.131 +        public JavaSource() {
   3.132 +            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
   3.133 +            source = template.replace("#T", qualifierArity.getType(typeArgumentKinds));
   3.134 +        }
   3.135 +
   3.136 +        @Override
   3.137 +        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   3.138 +            return source;
   3.139 +        }
   3.140 +    }
   3.141 +
   3.142 +    void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
   3.143 +        JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
   3.144 +                null, null, Arrays.asList(source));
   3.145 +        ct.parse();
   3.146 +        check();
   3.147 +    }
   3.148 +
   3.149 +    void check() {
   3.150 +
   3.151 +        boolean errorExpected = false;
   3.152 +
   3.153 +        for (int i = 0 ; i < qualifierArity.n - 1 ; i++) {
   3.154 +            if (typeArgumentKinds[i] == TypeArgumentKind.DIAMOND) {
   3.155 +                errorExpected = true;
   3.156 +                break;
   3.157 +            }
   3.158 +        }
   3.159 +
   3.160 +        if (errorExpected != diagChecker.errorFound) {
   3.161 +            throw new Error("invalid diagnostics for source:\n" +
   3.162 +                source.getCharContent(true) +
   3.163 +                "\nFound error: " + diagChecker.errorFound +
   3.164 +                "\nExpected error: " + errorExpected);
   3.165 +        }
   3.166 +    }
   3.167 +
   3.168 +    static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
   3.169 +
   3.170 +        boolean errorFound;
   3.171 +
   3.172 +        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   3.173 +            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
   3.174 +                errorFound = true;
   3.175 +            }
   3.176 +        }
   3.177 +    }
   3.178 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/test/tools/javac/generics/diamond/7030687/T7030687.java	Tue Mar 29 16:40:07 2011 +0100
     4.3 @@ -0,0 +1,19 @@
     4.4 +/*
     4.5 + * @test /nodynamiccopyright/
     4.6 + * @bug 7030687
     4.7 + * @summary Diamond: compiler accepts erroneous code where diamond is used with non-generic inner class
     4.8 + * @compile/fail/ref=T7030687.out -XDrawDiagnostics T7030687.java
     4.9 + */
    4.10 +
    4.11 +class T7030687<X> {
    4.12 +    class Member { }
    4.13 +    static class Nested {}
    4.14 +
    4.15 +    void test() {
    4.16 +        class Local {}
    4.17 +
    4.18 +        Member m = new Member<>();
    4.19 +        Nested n = new Nested<>();
    4.20 +        Local l = new Local<>();
    4.21 +    }
    4.22 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/test/tools/javac/generics/diamond/7030687/T7030687.out	Tue Mar 29 16:40:07 2011 +0100
     5.3 @@ -0,0 +1,4 @@
     5.4 +T7030687.java:15:30: compiler.err.cant.apply.diamond.1: T7030687<X>.Member, (compiler.misc.diamond.non.generic: T7030687<X>.Member)
     5.5 +T7030687.java:16:30: compiler.err.cant.apply.diamond.1: T7030687.Nested, (compiler.misc.diamond.non.generic: T7030687.Nested)
     5.6 +T7030687.java:17:28: compiler.err.cant.apply.diamond.1: Local, (compiler.misc.diamond.non.generic: Local)
     5.7 +3 errors

mercurial