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                     "Foo.java:25:15: compiler.warn.missing-explicit-ctor: pkg1.Foo.ProtectedFooNest, pkg1, mod",
 101                     "Foo.java:27:19: compiler.warn.missing-explicit-ctor: pkg1.Foo.ProtectedFooNest.ProtectedFooNestNest, pkg1, mod",
 102                     "5 warnings");
 103 
 104         // Warning enable,
 105         log = new JavacTask(tb)
 106             .options("-Xlint:missing-explicit-ctor", "-XDrawDiagnostics")
 107                 .outdir(classes)
 108                 .files(tb.findJavaFiles(src))
 109                 .run(Expect.SUCCESS)
 110                 .writeAll()
 111                 .getOutputLines(Task.OutputKind.DIRECT);
 112 
 113         if (!expected.equals(log)) {
 114             throw new AssertionError("Unexpected output: " + log);
 115         }
 116     }
 117 
 118     protected void runTests() throws Exception {
 119         runTests(m -> new Object[] { Paths.get(m.getName()).toAbsolutePath() });
 120     }
 121 
 122     private static final String MOD_INFO_SRC =
 123         """
 124         module mod {
 125             exports pkg1;
 126             // Do *not* export pkg2.
 127              exports pkg3 to java.base;
 128         }
 129         """;
 130 
 131     private static final String PKG1_BAR_SRC =
 132         """
 133         package pkg1;
 134 
 135         // Neither the top-level class nor the nested classes should generate
 136         // a warning since Bar is not public.
 137 
 138         // No explicit constructor; use a default.
 139         class Bar {
 140 
 141             // No explicit constructor; use a default.
 142             public class BarNest {
 143             }
 144 
 145             // No explicit constructor; use a default.
 146             public static class StaticBaryNest {
 147             }
 148 
 149             // No explicit constructor; use a default.
 150             protected class ProtectedBarNest {
 151             }
 152 
 153             // Package-access classes
 154 
 155             // No explicit constructor; use a default.
 156             /*package*/ class PkgBarNest {
 157             }
 158 
 159             // No explicit constructor; use a default.
 160             /*package*/ static class PkgStaticBarNest {
 161             }
 162             // Private classes
 163 
 164             // No explicit constructor; use a default.
 165             private class PrvBarNest {
 166             }
 167 
 168             // No explicit constructor; use a default.
 169             private static class PrvStaticBarNest {
 170             }
 171         }
 172         """;
 173 
 174     private  static final String PKG1_FOO_SRC =
 175         """
 176         package pkg1;
 177 
 178         // No explicit constructor; use a default.
 179         public class Foo {
 180 
 181             /*
 182              * Of the nexted classes, only FooNest and StaticFooNest should
 183              * generate warnings.
 184              */
 185 
 186             // No explicit constructor; use a default.
 187             public class FooNest {
 188             }
 189 
 190             // No explicit constructor; use a default.
 191             public static class StaticFooNest {
 192             }
 193 
 194             // No explicit constructor; use a default.
 195             @SuppressWarnings("missing-explicit-ctor")
 196             public static class SuppressedStaticFooNest {
 197             }
 198 
 199             // No explicit constructor; use a default.
 200             protected class ProtectedFooNest {
 201                 // No explicit constructor; use a default.
 202                 protected class ProtectedFooNestNest {}
 203             }
 204 
 205             // Package-access classes
 206 
 207             // No explicit constructor; use a default.
 208             /*package*/ class PkgFooNest {
 209                 // No explicit constructor; use a default.
 210                 protected class PkgFooNestNest {}
 211             }
 212 
 213             // No explicit constructor; use a default.
 214             /*package*/ static class PkgStaticFooNest {
 215             }
 216             // Private classes
 217 
 218             // No explicit constructor; use a default.
 219             private class PrvFooNest {
 220                 // No explicit constructor; use a default.
 221                 protected class PrvFooNestNest {}
 222             }
 223 
 224             // No explicit constructor; use a default.
 225             private static class PrvStaticFooNest {
 226             }
 227         }
 228         """;
 229 
 230     private static final String PKG2_BAZ_SRC =
 231         """
 232         package pkg2;
 233 
 234         // None of these classes should generate warnings since pkg2 is not
 235         // exported unconditionally.
 236 
 237         // No explicit constructor; use a default.
 238         public class Baz {
 239 
 240             // No explicit constructor; use a default.
 241             public class FooNest {
 242             }
 243 
 244             // No explicit constructor; use a default.
 245             public static class StaticFooNest {
 246             }
 247 
 248             // Package-access classes
 249 
 250             // No explicit constructor; use a default.
 251             /*package*/ class PkgFooNest {
 252             }
 253 
 254             // No explicit constructor; use a default.
 255             /*package*/ static class PkgStaticFooNest {
 256             }
 257             // Private classes
 258 
 259             // No explicit constructor; use a default.
 260             private class PrvFooNest {
 261             }
 262 
 263             // No explicit constructor; use a default.
 264             private static class PrvStaticFooNest {
 265             }
 266         }
 267         """;
 268 
 269     private static final String PKG2_QUUX_SRC =
 270         """
 271         package pkg2;
 272 
 273         // Neither the top-level class nor the nested classes should generate
 274         // a warning since Bar is not public.
 275 
 276         // No explicit constructor; use a default.
 277         class Quux {
 278 
 279             // No explicit constructor; use a default.
 280             public class FooNest {
 281             }
 282 
 283             // No explicit constructor; use a default.
 284             public static class StaticFooNest {
 285             }
 286 
 287             // Package-access classes
 288 
 289             // No explicit constructor; use a default.
 290             /*package*/ class PkgFooNest {
 291             }
 292 
 293             // No explicit constructor; use a default.
 294             /*package*/ static class PkgStaticFooNest {
 295             }
 296             // Private classes
 297 
 298             // No explicit constructor; use a default.
 299             private class PrvFooNest {
 300             }
 301 
 302             // No explicit constructor; use a default.
 303             private static class PrvStaticFooNest {
 304             }
 305         }
 306         """;
 307 
 308     private static final String PKG3_CORGE_SRC =
 309         """
 310         package pkg3;
 311 
 312         // None of these classes should generate warnings since pkg3 is not
 313         // exported unconditionally.
 314 
 315         // No explicit constructor; use a default.
 316         public class Corge {
 317 
 318             // No explicit constructor; use a default.
 319             public class FooNest {
 320             }
 321 
 322             // No explicit constructor; use a default.
 323             public static class StaticFooNest {
 324             }
 325 
 326             // Package-access classes
 327 
 328             // No explicit constructor; use a default.
 329             /*package*/ class PkgFooNest {
 330             }
 331 
 332             // No explicit constructor; use a default.
 333             /*package*/ static class PkgStaticFooNest {
 334             }
 335             // Private classes
 336 
 337             // No explicit constructor; use a default.
 338             private class PrvFooNest {
 339             }
 340 
 341             // No explicit constructor; use a default.
 342             private static class PrvStaticFooNest {
 343             }
 344         }
 345         """;
 346 
 347     private static final String PKG3_GRAULT_SRC =
 348         """
 349         package pkg3;
 350 
 351         // None of these classes should generate warnings since pkg3 is not
 352         // exported unconditionally.
 353 
 354         // No explicit constructor; use a default.
 355         class Grault {
 356 
 357             // No explicit constructor; use a default.
 358             public class FooNest {
 359             }
 360 
 361             // No explicit constructor; use a default.
 362             public static class StaticFooNest {
 363             }
 364 
 365             // Package-access classes
 366 
 367             // No explicit constructor; use a default.
 368             /*package*/ class PkgFooNest {
 369             }
 370 
 371             // No explicit constructor; use a default.
 372             /*package*/ static class PkgStaticFooNest {
 373             }
 374             // Private classes
 375 
 376             // No explicit constructor; use a default.
 377             private class PrvFooNest {
 378             }
 379 
 380             // No explicit constructor; use a default.
 381             private static class PrvStaticFooNest {
 382             }
 383         }
 384         """;
 385 }