1 /*
   2  * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 8071961
  27  * @summary Verify expected default constructor warnings are producted or not produced
  28  * @library /tools/lib
  29  * @modules jdk.compiler/com.sun.tools.javac.api
  30  *          jdk.compiler/com.sun.tools.javac.main
  31  * @build toolbox.ToolBox toolbox.JavacTask toolbox.TestRunner
  32  * @run main DefaultCtorWarningToolBox
  33  */
  34 
  35 import java.io.IOException;
  36 import java.nio.file.Path;
  37 import java.nio.file.Paths;
  38 import java.util.Arrays;
  39 import java.util.List;
  40 
  41 import java.io.InputStream;
  42 import java.nio.file.Files;
  43 import java.util.EnumSet;
  44 import javax.tools.JavaFileManager;
  45 import javax.tools.JavaFileObject;
  46 import javax.tools.StandardLocation;
  47 import javax.tools.ToolProvider;
  48 import toolbox.JavacTask;
  49 import toolbox.Task;
  50 import toolbox.Task.Expect;
  51 import toolbox.TestRunner;
  52 import toolbox.ToolBox;
  53 
  54 public class DefaultCtorWarningToolBox extends TestRunner {
  55 
  56     private final ToolBox tb = new ToolBox();
  57     private final String fileSep = System.getProperty("file.separator");
  58 
  59     public DefaultCtorWarningToolBox() {
  60         super(System.err);
  61     }
  62 
  63     public static void main(String... args) throws Exception {
  64         new DefaultCtorWarningToolBox().runTests();
  65     }
  66 
  67     @Test
  68     public void testWithAndWithOutLint(Path base) throws IOException {
  69         Path src = base.resolve("src");
  70 
  71         tb.writeJavaFiles(src,
  72                           MOD_INFO_SRC,
  73                           PKG1_BAR_SRC, PKG1_FOO_SRC,
  74                           PKG2_BAZ_SRC, PKG2_QUUX_SRC,
  75                           PKG3_CORGE_SRC, PKG3_GRAULT_SRC
  76                           );
  77         Path classes = base.resolve("classes");
  78         tb.createDirectories(classes);
  79 
  80         List<String> log;
  81         List<String> expected = List.of("");
  82 
  83         // Warning disabled, no messages expected
  84         log = new JavacTask(tb)
  85                 .options("-Xlint:-missing-explicit-ctor", "-Werror")
  86                 .outdir(classes)
  87                 .files(tb.findJavaFiles(src))
  88                 .run(Expect.SUCCESS)
  89                 .writeAll()
  90                 .getOutputLines(Task.OutputKind.DIRECT);
  91 
  92         if (!expected.equals(log)) {
  93             throw new AssertionError("Unexpected output: " + log);
  94         }
  95 
  96         expected =
  97             List.of("Foo.java:4:8: compiler.warn.missing-explicit-ctor: pkg1.Foo, pkg1, mod",
  98                     "Foo.java:12:12: compiler.warn.missing-explicit-ctor: pkg1.Foo.FooNest, pkg1, mod",
  99                     "Foo.java:16:19: compiler.warn.missing-explicit-ctor: pkg1.Foo.StaticFooNest, pkg1, mod",
 100                     "3 warnings");
 101 
 102         // Warning enable,
 103         log = new JavacTask(tb)
 104             .options("-Xlint:missing-explicit-ctor", "-XDrawDiagnostics")
 105                 .outdir(classes)
 106                 .files(tb.findJavaFiles(src))
 107                 .run(Expect.SUCCESS)
 108                 .writeAll()
 109                 .getOutputLines(Task.OutputKind.DIRECT);
 110 
 111         if (!expected.equals(log)) {
 112             throw new AssertionError("Unexpected output: " + log);
 113         }
 114     }
 115 
 116     protected void runTests() throws Exception {
 117         runTests(m -> new Object[] { Paths.get(m.getName()).toAbsolutePath() });
 118     }
 119 
 120     private static final String MOD_INFO_SRC =
 121         """
 122         module mod {
 123             exports pkg1;
 124             // Do *not* export pkg2.
 125              exports pkg3 to java.base;
 126         }
 127         """;
 128 
 129     private static final String PKG1_BAR_SRC =
 130         """
 131         package pkg1;
 132 
 133         // Neither the top-level class nor the nested classes should generate
 134         // a warning since Bar is not public.
 135 
 136         // No explicit constructor; use a default.
 137         class Bar {
 138 
 139             // No explicit constructor; use a default.
 140             public class FooNest {
 141             }
 142 
 143             // No explicit constructor; use a default.
 144             public static class StaticFooNest {
 145             }
 146 
 147             // Package-access classes
 148 
 149             // No explicit constructor; use a default.
 150             /*package*/ class PkgFooNest {
 151             }
 152 
 153             // No explicit constructor; use a default.
 154             /*package*/ static class PkgStaticFooNest {
 155             }
 156             // Private classes
 157 
 158             // No explicit constructor; use a default.
 159             private class PrvFooNest {
 160             }
 161 
 162             // No explicit constructor; use a default.
 163             private static class PrvStaticFooNest {
 164             }
 165         }
 166         """;
 167 
 168     private  static final String PKG1_FOO_SRC =
 169         """
 170         package pkg1;
 171 
 172         // No explicit constructor; use a default.
 173         public class Foo {
 174 
 175             /*
 176              * Of the nexted classes, only FooNest and StaticFooNest should
 177              * generate warnings.
 178              */
 179 
 180             // No explicit constructor; use a default.
 181             public class FooNest {
 182             }
 183 
 184             // No explicit constructor; use a default.
 185             public static class StaticFooNest {
 186             }
 187 
 188             // No explicit constructor; use a default.
 189             @SuppressWarnings("missing-explicit-ctor")
 190             public static class SuppressedStaticFooNest {
 191             }
 192 
 193             // Package-access classes
 194 
 195             // No explicit constructor; use a default.
 196             /*package*/ class PkgFooNest {
 197             }
 198 
 199             // No explicit constructor; use a default.
 200             /*package*/ static class PkgStaticFooNest {
 201             }
 202             // Private classes
 203 
 204             // No explicit constructor; use a default.
 205             private class PrvFooNest {
 206             }
 207 
 208             // No explicit constructor; use a default.
 209             private static class PrvStaticFooNest {
 210             }
 211         }
 212         """;
 213 
 214     private static final String PKG2_BAZ_SRC =
 215         """
 216         package pkg2;
 217 
 218         // None of these classes should generate warnings since pkg2 is not
 219         // exported unconditionally.
 220 
 221         // No explicit constructor; use a default.
 222         public class Baz {
 223 
 224             // No explicit constructor; use a default.
 225             public class FooNest {
 226             }
 227 
 228             // No explicit constructor; use a default.
 229             public static class StaticFooNest {
 230             }
 231 
 232             // Package-access classes
 233 
 234             // No explicit constructor; use a default.
 235             /*package*/ class PkgFooNest {
 236             }
 237 
 238             // No explicit constructor; use a default.
 239             /*package*/ static class PkgStaticFooNest {
 240             }
 241             // Private classes
 242 
 243             // No explicit constructor; use a default.
 244             private class PrvFooNest {
 245             }
 246 
 247             // No explicit constructor; use a default.
 248             private static class PrvStaticFooNest {
 249             }
 250         }
 251         """;
 252 
 253     private static final String PKG2_QUUX_SRC =
 254         """
 255         package pkg2;
 256 
 257         // Neither the top-level class nor the nested classes should generate
 258         // a warning since Bar is not public.
 259 
 260         // No explicit constructor; use a default.
 261         class Quux {
 262 
 263             // No explicit constructor; use a default.
 264             public class FooNest {
 265             }
 266 
 267             // No explicit constructor; use a default.
 268             public static class StaticFooNest {
 269             }
 270 
 271             // Package-access classes
 272 
 273             // No explicit constructor; use a default.
 274             /*package*/ class PkgFooNest {
 275             }
 276 
 277             // No explicit constructor; use a default.
 278             /*package*/ static class PkgStaticFooNest {
 279             }
 280             // Private classes
 281 
 282             // No explicit constructor; use a default.
 283             private class PrvFooNest {
 284             }
 285 
 286             // No explicit constructor; use a default.
 287             private static class PrvStaticFooNest {
 288             }
 289         }
 290         """;
 291 
 292     private static final String PKG3_CORGE_SRC =
 293         """
 294         package pkg3;
 295 
 296         // None of these classes should generate warnings since pkg3 is not
 297         // exported unconditionally.
 298 
 299         // No explicit constructor; use a default.
 300         public class Corge {
 301 
 302             // No explicit constructor; use a default.
 303             public class FooNest {
 304             }
 305 
 306             // No explicit constructor; use a default.
 307             public static class StaticFooNest {
 308             }
 309 
 310             // Package-access classes
 311 
 312             // No explicit constructor; use a default.
 313             /*package*/ class PkgFooNest {
 314             }
 315 
 316             // No explicit constructor; use a default.
 317             /*package*/ static class PkgStaticFooNest {
 318             }
 319             // Private classes
 320 
 321             // No explicit constructor; use a default.
 322             private class PrvFooNest {
 323             }
 324 
 325             // No explicit constructor; use a default.
 326             private static class PrvStaticFooNest {
 327             }
 328         }
 329         """;
 330 
 331     private static final String PKG3_GRAULT_SRC =
 332         """
 333         package pkg3;
 334 
 335         // None of these classes should generate warnings since pkg3 is not
 336         // exported unconditionally.
 337 
 338         // No explicit constructor; use a default.
 339         class Grault {
 340 
 341             // No explicit constructor; use a default.
 342             public class FooNest {
 343             }
 344 
 345             // No explicit constructor; use a default.
 346             public static class StaticFooNest {
 347             }
 348 
 349             // Package-access classes
 350 
 351             // No explicit constructor; use a default.
 352             /*package*/ class PkgFooNest {
 353             }
 354 
 355             // No explicit constructor; use a default.
 356             /*package*/ static class PkgStaticFooNest {
 357             }
 358             // Private classes
 359 
 360             // No explicit constructor; use a default.
 361             private class PrvFooNest {
 362             }
 363 
 364             // No explicit constructor; use a default.
 365             private static class PrvStaticFooNest {
 366             }
 367         }
 368         """;
 369 }