8145471: javac changes for enhanced deprecation
authorjjg
Thu, 20 Oct 2016 13:44:51 -0700
changeset 41637 7b24b4c32ee6
parent 41636 086a3c7a6b56
child 41638 7b8819e22551
8145471: javac changes for enhanced deprecation Reviewed-by: smarks, tbell, mcimadamore, jlahoda
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Options.java
langtools/test/tools/javac/diags/examples/RemovalFilename.java
langtools/test/tools/javac/diags/examples/RemovalFilenameAdditional.java
langtools/test/tools/javac/diags/examples/RemovalPlural/RemovalClass.java
langtools/test/tools/javac/diags/examples/RemovalPlural/RemovalFilename.java
langtools/test/tools/javac/diags/examples/RemovalPlural/RemovalPlural.java
langtools/test/tools/javac/diags/examples/RemovalPluralAdditional/RemovalClass.java
langtools/test/tools/javac/diags/examples/RemovalPluralAdditional/RemovalFilename.java
langtools/test/tools/javac/diags/examples/RemovalPluralAdditional/RemovalPlural.java
langtools/test/tools/javac/diags/examples/RemovalPluralAdditional/RemovalPluralAdditional.java
langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations.java
langtools/test/tools/javac/profiles/ProfileOptionTest.java
langtools/test/tools/javac/warnings/Removal.java
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Thu Oct 20 20:01:40 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Thu Oct 20 13:44:51 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -113,7 +113,7 @@
      * Internal compiler flags (no bits in the lower 16).
      *****************************************/
 
-    /** Flag is set if symbol is deprecated.
+    /** Flag is set if symbol is deprecated.  See also DEPRECATED_REMOVAL.
      */
     public static final int DEPRECATED   = 1<<17;
 
@@ -293,6 +293,11 @@
      */
     public static final long SYSTEM_MODULE = 1L<<53;
 
+    /**
+     * Flag to indicate the given symbol has been deprecated and marked for removal.
+     */
+    public static final long DEPRECATED_REMOVAL = 1L<<54;
+
     /** Modifier masks.
      */
     public static final int
@@ -402,7 +407,8 @@
         THROWS(Flags.THROWS),
         LAMBDA_METHOD(Flags.LAMBDA_METHOD),
         TYPE_TRANSLATED(Flags.TYPE_TRANSLATED),
-        MODULE(Flags.MODULE);
+        MODULE(Flags.MODULE),
+        DEPRECATED_REMOVAL(Flags.DEPRECATED_REMOVAL);
 
         Flag(long flag) {
             this.value = flag;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java	Thu Oct 20 20:01:40 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java	Thu Oct 20 13:44:51 2016 -0700
@@ -25,11 +25,13 @@
 
 package com.sun.tools.javac.code;
 
+import java.util.Arrays;
 import java.util.EnumSet;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.main.Option;
 import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.util.Options;
@@ -81,12 +83,13 @@
     }
 
     /**
-     * Returns a new Lint that has the given LintCategory suppressed.
+     * Returns a new Lint that has the given LintCategorys suppressed.
+     * @param lc one or more categories to be suppressed
      */
-    public Lint suppress(LintCategory lc) {
+    public Lint suppress(LintCategory... lc) {
         Lint l = new Lint(this);
-        l.values.remove(lc);
-        l.suppressedValues.add(lc);
+        l.values.removeAll(Arrays.asList(lc));
+        l.suppressedValues.addAll(Arrays.asList(lc));
         return l;
     }
 
@@ -100,10 +103,31 @@
     protected Lint(Context context) {
         // initialize values according to the lint options
         Options options = Options.instance(context);
-        values = EnumSet.noneOf(LintCategory.class);
-        for (Map.Entry<String, LintCategory> e: map.entrySet()) {
-            if (options.lint(e.getKey()))
-                values.add(e.getValue());
+
+        if (options.isSet(Option.XLINT) || options.isSet(Option.XLINT_CUSTOM, "all")) {
+            // If -Xlint or -Xlint:all is given, enable all categories by default
+            values = EnumSet.allOf(LintCategory.class);
+        } else if (options.isSet(Option.XLINT_CUSTOM, "none")) {
+            // if -Xlint:none is given, disable all categories by default
+            values = EnumSet.noneOf(LintCategory.class);
+        } else {
+            // otherwise, enable on-by-default categories
+            values = EnumSet.noneOf(LintCategory.class);
+
+            Source source = Source.instance(context);
+            if (source.compareTo(Source.JDK1_9) >= 0) {
+                values.add(LintCategory.DEP_ANN);
+            }
+            values.add(LintCategory.REMOVAL);
+        }
+
+        // Look for specific overrides
+        for (LintCategory lc : LintCategory.values()) {
+            if (options.isSet(Option.XLINT_CUSTOM, lc.option)) {
+                values.add(lc);
+            } else if (options.isSet(Option.XLINT_CUSTOM, "-" + lc.option)) {
+                values.remove(lc);
+            }
         }
 
         suppressedValues = EnumSet.noneOf(LintCategory.class);
@@ -213,6 +237,11 @@
         RAW("rawtypes"),
 
         /**
+         * Warn about use of deprecated-for-removal items.
+         */
+        REMOVAL("removal"),
+
+        /**
          * Warn about Serializable classes that do not provide a serial version ID.
          */
         SERIAL("serial"),
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Thu Oct 20 20:01:40 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Thu Oct 20 13:44:51 2016 -0700
@@ -359,6 +359,10 @@
         return (flags_field & DEPRECATED) != 0;
     }
 
+    public boolean isDeprecatedForRemoval() {
+        return (flags_field & DEPRECATED_REMOVAL) != 0;
+    }
+
     public boolean isDeprecatableViaAnnotation() {
         switch (getKind()) {
             case LOCAL_VARIABLE:
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java	Thu Oct 20 20:01:40 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java	Thu Oct 20 13:44:51 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -340,6 +340,13 @@
                     && toAnnotate.owner.kind != MTH
                     && types.isSameType(c.type, syms.deprecatedType)) {
                 toAnnotate.flags_field |= Flags.DEPRECATED;
+                Attribute fr = c.member(names.forRemoval);
+                if (fr instanceof Attribute.Constant) {
+                    Attribute.Constant v = (Attribute.Constant) fr;
+                    if (v.type == syms.booleanType && ((Integer) v.value) != 0) {
+                        toAnnotate.flags_field |= Flags.DEPRECATED_REMOVAL;
+                    }
+                }
             }
         }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Thu Oct 20 20:01:40 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Thu Oct 20 13:44:51 2016 -0700
@@ -139,11 +139,14 @@
         profile = Profile.instance(context);
 
         boolean verboseDeprecated = lint.isEnabled(LintCategory.DEPRECATION);
+        boolean verboseRemoval = lint.isEnabled(LintCategory.REMOVAL);
         boolean verboseUnchecked = lint.isEnabled(LintCategory.UNCHECKED);
         boolean enforceMandatoryWarnings = true;
 
         deprecationHandler = new MandatoryWarningHandler(log, verboseDeprecated,
                 enforceMandatoryWarnings, "deprecated", LintCategory.DEPRECATION);
+        removalHandler = new MandatoryWarningHandler(log, verboseRemoval,
+                enforceMandatoryWarnings, "removal", LintCategory.REMOVAL);
         uncheckedHandler = new MandatoryWarningHandler(log, verboseUnchecked,
                 enforceMandatoryWarnings, "unchecked", LintCategory.UNCHECKED);
         sunApiHandler = new MandatoryWarningHandler(log, false,
@@ -185,6 +188,10 @@
      */
     private MandatoryWarningHandler deprecationHandler;
 
+    /** A handler for messages about deprecated-for-removal usage.
+     */
+    private MandatoryWarningHandler removalHandler;
+
     /** A handler for messages about unchecked or unsafe usage.
      */
     private MandatoryWarningHandler uncheckedHandler;
@@ -218,8 +225,13 @@
      *  @param sym        The deprecated symbol.
      */
     void warnDeprecated(DiagnosticPosition pos, Symbol sym) {
-        if (!lint.isSuppressed(LintCategory.DEPRECATION))
+        if (sym.isDeprecatedForRemoval()) {
+            if (!lint.isSuppressed(LintCategory.REMOVAL)) {
+                removalHandler.report(pos, "has.been.deprecated.for.removal", sym, sym.location());
+            }
+        } else if (!lint.isSuppressed(LintCategory.DEPRECATION)) {
             deprecationHandler.report(pos, "has.been.deprecated", sym, sym.location());
+        }
     }
 
     /** Warn about unchecked operation.
@@ -257,6 +269,7 @@
      */
     public void reportDeferredDiagnostics() {
         deprecationHandler.reportDeferredDiagnostic();
+        removalHandler.reportDeferredDiagnostic();
         uncheckedHandler.reportDeferredDiagnostic();
         sunApiHandler.reportDeferredDiagnostic();
     }
@@ -3230,9 +3243,9 @@
     }
 
     void checkDeprecated(final DiagnosticPosition pos, final Symbol other, final Symbol s) {
-        if ((s.flags() & DEPRECATED) != 0 &&
-                (other.flags() & DEPRECATED) == 0 &&
-                s.outermostClass() != other.outermostClass()) {
+        if ( (s.isDeprecatedForRemoval()
+                || s.isDeprecated() && !other.isDeprecated())
+              && s.outermostClass() != other.outermostClass()) {
             deferredLintHandler.report(new DeferredLintHandler.LintLogger() {
                 @Override
                 public void report() {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Thu Oct 20 20:01:40 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Thu Oct 20 13:44:51 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -103,7 +103,6 @@
     private final TypeAnnotations typeAnnotations;
     private final Types types;
     private final JCDiagnostic.Factory diags;
-    private final Source source;
     private final DeferredLintHandler deferredLintHandler;
     private final Lint lint;
     private final TypeEnvs typeEnvs;
@@ -131,7 +130,6 @@
         typeAnnotations = TypeAnnotations.instance(context);
         types = Types.instance(context);
         diags = JCDiagnostic.Factory.instance(context);
-        source = Source.instance(context);
         deferredLintHandler = DeferredLintHandler.instance(context);
         lint = Lint.instance(context);
         typeEnvs = TypeEnvs.instance(context);
@@ -178,6 +176,7 @@
     /** Complete entering a class.
      *  @param sym         The symbol of the class to be completed.
      */
+    @Override
     public void complete(Symbol sym) throws CompletionFailure {
         // Suppress some (recursive) MemberEnter invocations
         if (!completionEnabled) {
@@ -414,7 +413,7 @@
         Type attribImportType(JCTree tree, Env<AttrContext> env) {
             Assert.check(completionEnabled);
             Lint prevLint = chk.setLint(allowDeprecationOnImport ?
-                    lint : lint.suppress(LintCategory.DEPRECATION));
+                    lint : lint.suppress(LintCategory.DEPRECATION, LintCategory.REMOVAL));
             try {
                 // To prevent deep recursion, suppress completion of some
                 // types.
@@ -751,12 +750,12 @@
             // can attribute the annotation types and then check to see if the
             // @Deprecated annotation is present.
             attr.attribAnnotationTypes(tree.mods.annotations, baseEnv);
-            if (hasDeprecatedAnnotation(tree.mods.annotations))
-                sym.flags_field |= DEPRECATED;
+            handleDeprecatedAnnotation(tree.mods.annotations, sym);
 
             chk.checkNonCyclicDecl(tree);
         }
             //where:
+            @Override
             protected JCExpression clearTypeParams(JCExpression superType) {
                 switch (superType.getTag()) {
                     case TYPEAPPLY:
@@ -767,16 +766,29 @@
             }
 
             /**
-             * Check if a list of annotations contains a reference to
-             * java.lang.Deprecated.
+             * If a list of annotations contains a reference to java.lang.Deprecated,
+             * set the DEPRECATED flag.
+             * If the annotation is marked forRemoval=true, also set DEPRECATED_REMOVAL.
              **/
-            private boolean hasDeprecatedAnnotation(List<JCAnnotation> annotations) {
+            private void handleDeprecatedAnnotation(List<JCAnnotation> annotations, Symbol sym) {
                 for (List<JCAnnotation> al = annotations; !al.isEmpty(); al = al.tail) {
                     JCAnnotation a = al.head;
-                    if (a.annotationType.type == syms.deprecatedType && a.args.isEmpty())
-                        return true;
+                    if (a.annotationType.type == syms.deprecatedType) {
+                        sym.flags_field |= Flags.DEPRECATED;
+                        a.args.stream()
+                                .filter(e -> e.hasTag(ASSIGN))
+                                .map(e -> (JCAssign) e)
+                                .filter(assign -> TreeInfo.name(assign.lhs) == names.forRemoval)
+                                .findFirst()
+                                .ifPresent(assign -> {
+                                    JCExpression rhs = TreeInfo.skipParens(assign.rhs);
+                                    if (rhs.hasTag(LITERAL)
+                                            && Boolean.TRUE.equals(((JCLiteral) rhs).getValue())) {
+                                        sym.flags_field |= DEPRECATED_REMOVAL;
+                                    }
+                                });
+                    }
                 }
-                return false;
             }
 
         @Override
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java	Thu Oct 20 20:01:40 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java	Thu Oct 20 13:44:51 2016 -0700
@@ -52,8 +52,6 @@
 import javax.tools.JavaFileObject;
 import javax.tools.JavaFileObject.Kind;
 
-import com.sun.tools.javac.code.Lint;
-import com.sun.tools.javac.code.Source;
 import com.sun.tools.javac.main.Option;
 import com.sun.tools.javac.main.OptionHelper;
 import com.sun.tools.javac.main.OptionHelper.GrumpyHelper;
@@ -85,7 +83,10 @@
         log = Log.instance(context);
         options = Options.instance(context);
         classLoaderClass = options.get("procloader");
-        locations.update(log, Lint.instance(context), FSInfo.instance(context));
+
+        // Avoid initializing Lint
+        boolean warn = options.isLintSet("path");
+        locations.update(log, warn, FSInfo.instance(context));
 
         // Setting this option is an indication that close() should defer actually closing
         // the file manager until after a specified period of inactivity.
@@ -171,14 +172,6 @@
     private long lastUsedTime = System.currentTimeMillis();
     protected long deferredCloseTimeout = 0;
 
-    protected Source getSource() {
-        String sourceName = options.get(Option.SOURCE);
-        Source source = null;
-        if (sourceName != null)
-            source = Source.lookup(sourceName);
-        return (source != null ? source : Source.DEFAULT);
-    }
-
     protected ClassLoader getClassLoader(URL[] urls) {
         ClassLoader thisClassLoader = getClass().getClassLoader();
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java	Thu Oct 20 20:01:40 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java	Thu Oct 20 13:44:51 2016 -0700
@@ -42,7 +42,6 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.ProviderNotFoundException;
-import java.nio.file.spi.FileSystemProvider;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -63,7 +62,6 @@
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
-import java.util.zip.ZipFile;
 
 import javax.lang.model.SourceVersion;
 import javax.tools.JavaFileManager;
@@ -159,10 +157,9 @@
         }
     }
 
-    // could replace Lint by "boolean warn"
-    void update(Log log, Lint lint, FSInfo fsInfo) {
+    void update(Log log, boolean warn, FSInfo fsInfo) {
         this.log = log;
-        warn = lint.isEnabled(Lint.LintCategory.PATH);
+        this.warn = warn;
         this.fsInfo = fsInfo;
     }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Thu Oct 20 20:01:40 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Thu Oct 20 13:44:51 2016 -0700
@@ -1460,7 +1460,6 @@
             ListBuffer<CompoundAnnotationProxy> proxies = new ListBuffer<>();
             for (int i = 0; i<numAttributes; i++) {
                 CompoundAnnotationProxy proxy = readCompoundAnnotation();
-
                 if (proxy.type.tsym == syms.proprietaryType.tsym)
                     sym.flags_field |= PROPRIETARY;
                 else if (proxy.type.tsym == syms.profileType.tsym) {
@@ -1479,6 +1478,16 @@
                         target = proxy;
                     } else if (proxy.type.tsym == syms.repeatableType.tsym) {
                         repeatable = proxy;
+                    } else if (proxy.type.tsym == syms.deprecatedType.tsym) {
+                        sym.flags_field |= DEPRECATED;
+                        for (Pair<Name, Attribute> v : proxy.values) {
+                            if (v.fst == names.forRemoval && v.snd instanceof Attribute.Constant) {
+                                Attribute.Constant c = (Attribute.Constant) v.snd;
+                                if (c.type == syms.booleanType && ((Integer) c.value) != 0) {
+                                    sym.flags_field |= DEPRECATED_REMOVAL;
+                                }
+                            }
+                        }
                     }
 
                     proxies.append(proxy);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java	Thu Oct 20 20:01:40 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java	Thu Oct 20 13:44:51 2016 -0700
@@ -37,6 +37,7 @@
 import java.util.EnumSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.Locale;
 import java.util.Map;
 import java.util.ServiceLoader;
@@ -111,7 +112,6 @@
                                             "all",
                                             log.localize(PrefixKind.JAVAC, "opt.Xlint.all")));
             for (LintCategory lc : LintCategory.values()) {
-                if (lc.hidden) continue;
                 log.printRawLines(WriterKind.STDOUT,
                                   String.format(LINT_KEY_FORMAT,
                                                 lc.option,
@@ -801,8 +801,8 @@
     /** The kind of choices for this option, if any. */
     private final ChoiceKind choiceKind;
 
-    /** The choices for this option, if any, and whether or not the choices are hidden. */
-    private final Map<String,Boolean> choices;
+    /** The choices for this option, if any. */
+    private final Set<String> choices;
 
     /**
      * Looks up the first option matching the given argument in the full set of options.
@@ -815,7 +815,8 @@
 
     /**
      * Looks up the first option matching the given argument within a set of options.
-     * @param arg the argument to be matches
+     * @param arg the argument to be matched
+     * @param options the set of possible options
      * @return the first option that matches, or null if none.
      */
     public static Option lookup(String arg, Set<Option> options) {
@@ -867,7 +868,7 @@
     }
 
     Option(String text, String argsNameKey, String descrKey, OptionKind kind, OptionGroup group,
-            ChoiceKind choiceKind, Map<String,Boolean> choices) {
+            ChoiceKind choiceKind, Set<String> choices) {
         this(text, argsNameKey, descrKey, kind, group, choiceKind, choices, ArgKind.REQUIRED);
     }
 
@@ -875,19 +876,12 @@
             OptionKind kind, OptionGroup group,
             ChoiceKind choiceKind, String... choices) {
         this(text, null, descrKey, kind, group, choiceKind,
-                createChoices(choices), ArgKind.REQUIRED);
+                new LinkedHashSet<>(Arrays.asList(choices)), ArgKind.REQUIRED);
     }
-    // where
-        private static Map<String,Boolean> createChoices(String... choices) {
-            Map<String,Boolean> map = new LinkedHashMap<>();
-            for (String c: choices)
-                map.put(c, false);
-            return map;
-        }
 
     private Option(String text, String argsNameKey, String descrKey,
             OptionKind kind, OptionGroup group,
-            ChoiceKind choiceKind, Map<String,Boolean> choices,
+            ChoiceKind choiceKind, Set<String> choices,
             ArgKind argKind) {
         this.names = text.trim().split("\\s+");
         Assert.check(names.length >= 1);
@@ -943,10 +937,10 @@
         if (choices != null) {
             String arg = option.substring(name.length());
             if (choiceKind == ChoiceKind.ONEOF)
-                return choices.keySet().contains(arg);
+                return choices.contains(arg);
             else {
                 for (String a: arg.split(",+")) {
-                    if (!choices.keySet().contains(a))
+                    if (!choices.contains(a))
                         return false;
                 }
             }
@@ -1016,7 +1010,7 @@
         if (choices != null) {
             if (choiceKind == ChoiceKind.ONEOF) {
                 // some clients like to see just one of option+choice set
-                for (String s: choices.keySet())
+                for (String s : choices)
                     helper.remove(primaryName + s);
                 String opt = primaryName + arg;
                 helper.put(opt, opt);
@@ -1113,12 +1107,10 @@
         if (argsNameKey == null) {
             if (choices != null) {
                 String sep = "{";
-                for (Map.Entry<String,Boolean> e: choices.entrySet()) {
-                    if (!e.getValue()) {
-                        sb.append(sep);
-                        sb.append(e.getKey());
-                        sep = ",";
-                    }
+                for (String choice : choices) {
+                    sb.append(sep);
+                    sb.append(choices);
+                    sep = ",";
                 }
                 sb.append("}");
             }
@@ -1163,14 +1155,14 @@
         }
     }
 
-    private static Map<String,Boolean> getXLintChoices() {
-        Map<String,Boolean> choices = new LinkedHashMap<>();
-        choices.put("all", false);
-        for (Lint.LintCategory c : Lint.LintCategory.values())
-            choices.put(c.option, c.hidden);
-        for (Lint.LintCategory c : Lint.LintCategory.values())
-            choices.put("-" + c.option, c.hidden);
-        choices.put("none", false);
+    private static Set<String> getXLintChoices() {
+        Set<String> choices = new LinkedHashSet<>();
+        choices.add("all");
+        for (Lint.LintCategory c : Lint.LintCategory.values()) {
+            choices.add(c.option);
+            choices.add("-" + c.option);
+        }
+        choices.add("none");
         return choices;
     }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Oct 20 20:01:40 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Oct 20 13:44:51 2016 -0700
@@ -1321,14 +1321,31 @@
     Some input files additionally use or override a deprecated API.
 
 # 0: file name
+compiler.note.removal.filename=\
+    {0} uses or overrides a deprecated API that is marked for removal.
+
+compiler.note.removal.plural=\
+    Some input files use or override a deprecated API that is marked for removal.
+
+# The following string may appear after one of the above removal messages.
+compiler.note.removal.recompile=\
+    Recompile with -Xlint:removal for details.
+
+# 0: file name
+compiler.note.removal.filename.additional=\
+    {0} has additional uses or overrides of a deprecated API that is marked for removal.
+
+compiler.note.removal.plural.additional=\
+    Some input files additionally use or override a deprecated API that is marked for removal.
+
+# 0: file name
 compiler.note.unchecked.filename=\
     {0} uses unchecked or unsafe operations.
 
 compiler.note.unchecked.plural=\
     Some input files use unchecked or unsafe operations.
 
-# The following string may appear after one of the above deprecation
-# messages.
+# The following string may appear after one of the above unchecked messages.
 compiler.note.unchecked.recompile=\
     Recompile with -Xlint:unchecked for details.
 
@@ -1441,6 +1458,10 @@
 compiler.warn.has.been.deprecated=\
     {0} in {1} has been deprecated
 
+# 0: symbol, 1: symbol
+compiler.warn.has.been.deprecated.for.removal=\
+    {0} in {1} has been deprecated and marked for removal
+
 # 0: symbol
 compiler.warn.sun.proprietary=\
     {0} is internal proprietary API and may be removed in a future release
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties	Thu Oct 20 20:01:40 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties	Thu Oct 20 13:44:51 2016 -0700
@@ -219,6 +219,9 @@
 javac.opt.Xlint.desc.rawtypes=\
     Warn about use of raw types.
 
+javac.opt.Xlint.desc.removal=\
+    Warn about use of API that has been marked for removal.
+
 javac.opt.Xlint.desc.serial=\
     Warn about Serializable classes that do not provide a serial version ID. \n\
 \                             Also warn about access to non-public members from a serializable element.
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Thu Oct 20 20:01:40 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Thu Oct 20 13:44:51 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -87,6 +87,7 @@
     public final Name family;
     public final Name finalize;
     public final Name forName;
+    public final Name forRemoval;
     public final Name getClass;
     public final Name getClassLoader;
     public final Name getComponentType;
@@ -242,6 +243,7 @@
         family = fromString("family");
         finalize = fromString("finalize");
         forName = fromString("forName");
+        forRemoval = fromString("forRemoval");
         getClass = fromString("getClass");
         getClassLoader = fromString("getClassLoader");
         getComponentType = fromString("getComponentType");
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Options.java	Thu Oct 20 20:01:40 2016 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Options.java	Thu Oct 20 13:44:51 2016 -0700
@@ -27,7 +27,6 @@
 
 import java.util.*;
 
-import com.sun.tools.javac.code.Source;
 import com.sun.tools.javac.main.Option;
 import static com.sun.tools.javac.main.Option.*;
 
@@ -113,6 +112,18 @@
         return (values.get(option.primaryName + value) != null);
     }
 
+    /** Check if the value for a lint option has been explicitly set, either with -Xlint:opt
+     *  or if all lint options have enabled and this one not disabled with -Xlint:-opt.
+     */
+    public boolean isLintSet(String s) {
+        // return true if either the specific option is enabled, or
+        // they are all enabled without the specific one being
+        // disabled
+        return
+            isSet(XLINT_CUSTOM, s) ||
+            (isSet(XLINT) || isSet(XLINT_CUSTOM, "all")) && isUnset(XLINT_CUSTOM, "-" + s);
+    }
+
     /**
      * Check if the value for an undocumented option has not been set.
      */
@@ -170,25 +181,4 @@
         for (Runnable r: listeners)
             r.run();
     }
-
-    /** Check for a lint suboption. */
-    public boolean lint(String s) {
-        // return true if either the specific option is enabled, or
-        // they are all enabled without the specific one being
-        // disabled
-        return
-            isSet(XLINT_CUSTOM, s) ||
-            (isSet(XLINT) || isSet(XLINT_CUSTOM, "all") || (s.equals("dep-ann") && depAnnOnByDefault())) &&
-                isUnset(XLINT_CUSTOM, "-" + s);
-    }
-        // where
-        private boolean depAnnOnByDefault() {
-            String sourceName = get(Option.SOURCE);
-            Source source = null;
-            if (sourceName != null)
-                source = Source.lookup(sourceName);
-            if (source == null)
-                source = Source.DEFAULT;
-            return source.compareTo(Source.JDK1_9) >= 0;
-        }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/RemovalFilename.java	Thu Oct 20 13:44:51 2016 -0700
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.note.removal.filename
+// key: compiler.note.removal.recompile
+// options: -Xlint:-removal
+
+class RemovalFilename {
+    RemovalClass d;
+}
+
+@Deprecated(forRemoval=true)
+class RemovalClass { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/RemovalFilenameAdditional.java	Thu Oct 20 13:44:51 2016 -0700
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.note.removal.filename.additional
+// key: compiler.warn.has.been.deprecated.for.removal
+// options: -Xmaxwarns 1
+
+class RemovalFilename {
+    RemovalClass d;
+}
+
+class RemovalFilenameAdditional {
+    RemovalClass d;
+}
+
+@Deprecated(forRemoval=true)
+class RemovalClass { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/RemovalPlural/RemovalClass.java	Thu Oct 20 13:44:51 2016 -0700
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+@Deprecated(forRemoval=true)
+class RemovalClass { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/RemovalPlural/RemovalFilename.java	Thu Oct 20 13:44:51 2016 -0700
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+class RemovalFileName {
+    RemovalClass d;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/RemovalPlural/RemovalPlural.java	Thu Oct 20 13:44:51 2016 -0700
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.note.removal.plural
+// key: compiler.note.removal.recompile
+// options: -Xlint:-removal
+
+class RemovalPlural {
+    RemovalClass d;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/RemovalPluralAdditional/RemovalClass.java	Thu Oct 20 13:44:51 2016 -0700
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+@Deprecated(forRemoval=true)
+class RemovalClass { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/RemovalPluralAdditional/RemovalFilename.java	Thu Oct 20 13:44:51 2016 -0700
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+class RemovalFileName {
+    RemovalClass d;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/RemovalPluralAdditional/RemovalPlural.java	Thu Oct 20 13:44:51 2016 -0700
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+class RemovalPlural {
+    RemovalClass d;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/RemovalPluralAdditional/RemovalPluralAdditional.java	Thu Oct 20 13:44:51 2016 -0700
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.note.removal.plural.additional
+// key: compiler.warn.has.been.deprecated.for.removal
+// options: -Xlint:deprecation -Xmaxwarns 1
+
+class RemovalPluralAdditional {
+    RemovalClass d;
+}
--- a/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations.java	Thu Oct 20 20:01:40 2016 +0000
+++ b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations.java	Thu Oct 20 13:44:51 2016 -0700
@@ -25,7 +25,7 @@
  * @test
  * @bug 8038455
  * @summary Verify that annotation processor can overwrite source and class files it generated
- *          during previous compilations, and that the Symbols are updated appropriatelly.
+ *          during previous compilations, and that the Symbols are updated appropriately.
  * @library /tools/lib /tools/javac/lib/
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
--- a/langtools/test/tools/javac/profiles/ProfileOptionTest.java	Thu Oct 20 20:01:40 2016 +0000
+++ b/langtools/test/tools/javac/profiles/ProfileOptionTest.java	Thu Oct 20 13:44:51 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -176,9 +176,14 @@
                             Arrays.asList(fo));
                     task.analyze();
 
-                    List<String> expectDiagCodes = (p.value >= e.getKey().value)
-                            ? Collections.<String>emptyList()
-                            : Arrays.asList("compiler.err.not.in.profile");
+                    List<String> expectDiagCodes = new ArrayList<>();
+                    if (fo.getName().equals("TPolicyFile.java")) {
+                        expectDiagCodes.add("compiler.warn.has.been.deprecated.for.removal");
+                    }
+
+                    if (p.value < e.getKey().value) {
+                        expectDiagCodes.add("compiler.err.not.in.profile");
+                    }
 
                     checkDiags(opts + " " + fo.getName(), dl.getDiagnostics(), expectDiagCodes);
                 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/warnings/Removal.java	Thu Oct 20 13:44:51 2016 -0700
@@ -0,0 +1,544 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8145471
+ * @summary javac changes for enhanced deprecation
+ * @library /tools/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ * @modules jdk.compiler/com.sun.tools.javac.main
+ * @build toolbox.JavacTask toolbox.TestRunner toolbox.ToolBox
+ * @run main Removal
+ */
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import toolbox.JavacTask;
+import toolbox.Task.Expect;
+import toolbox.Task.OutputKind;
+import toolbox.TestRunner;
+import toolbox.ToolBox;
+
+/*
+ * From JEP 277, JDK-8085614
+ *
+ *        use site     |      API declaration site
+ *        context      | not dep.   ord. dep.   term. dep.
+ *                     +----------------------------------
+ *        not dep.     |    N          W           W
+ *                     |
+ *        ord. dep.    |    N          N (2)       W (4)
+ *                     |
+ *        term. dep.   |    N          N (3)       W (5)
+ */
+
+public class Removal extends TestRunner {
+    public static void main(String... args) throws Exception {
+        Removal r = new Removal();
+        r.runTests(m -> new Object[] { Paths.get(m.getName()) });
+        r.report();
+    }
+
+    private final ToolBox tb = new ToolBox();
+    private final Path libSrc = Paths.get("lib").resolve("src");
+    private final Path libClasses = Paths.get("lib").resolve("classes");
+    int testCount = 0;
+
+    /**
+     * Options that may be used during compilation.
+     */
+    enum Options {
+        DEFAULT(),
+        XLINT_DEPRECATED("-Xlint:deprecation"),
+        XLINT_NO_REMOVAL("-Xlint:-removal");
+
+        Options(String... opts) {
+            this.opts = Arrays.asList(opts);
+        }
+
+        final List<String> opts;
+    }
+
+    /**
+     * The kind of deprecation.
+     */
+    enum DeprKind {
+        NONE("", null),
+        DEPRECATED("@Deprecated ", "compiler.warn.has.been.deprecated"),
+        REMOVAL("@Deprecated(forRemoval=true) ", "compiler.warn.has.been.deprecated.for.removal");
+        DeprKind(String anno, String warn) {
+            this.anno = anno;
+            this.warn = warn;
+        }
+        final String anno;
+        final String warn;
+    }
+
+    final String[] lib = {
+        "package lib; public class Class {\n"
+        + "    public static void method() { }\n"
+        + "    @Deprecated public static void depMethod() { }\n"
+        + "    @Deprecated(forRemoval=true) public static void remMethod() { }\n"
+        + "    public static int field;\n"
+        + "    @Deprecated public static int depField;\n"
+        + "    @Deprecated(forRemoval=true) public static int remField;\n"
+        + "}",
+        "package lib; @Deprecated public class DepClass { }",
+        "package lib; @Deprecated(forRemoval=true) public class RemClass { }"
+    };
+
+    /**
+     * The kind of declaration to be referenced at the use site.
+     */
+    enum RefKind {
+        CLASS("lib.%s c;", "Class", "DepClass", "RemClass"),
+        METHOD("{ lib.Class.%s(); }", "method", "depMethod", "remMethod"),
+        FIELD("int i = lib.Class.%s;", "field", "depField", "remField");
+
+        RefKind(String template, String def, String dep, String rem) {
+            fragments.put(DeprKind.NONE, String.format(template, def));
+            fragments.put(DeprKind.DEPRECATED, String.format(template, dep));
+            fragments.put(DeprKind.REMOVAL, String.format(template, rem));
+        }
+
+        String getFragment(DeprKind k) {
+            return fragments.get(k);
+        }
+
+        private final Map<DeprKind, String> fragments = new EnumMap<>(DeprKind.class);
+    }
+
+    /**
+     * Get source code for a reference to a possibly-deprecated item declared in a library.
+     * @param refKind the kind of element (class, method, field) being referenced
+     * @param declDeprKind the kind of deprecation on the declaration of the item being referenced
+     * @param useDeprKind the kind of deprecation enclosing the use site
+     * @return
+     */
+    static String getSource(RefKind refKind, DeprKind declDeprKind, DeprKind useDeprKind) {
+        return "package p; "
+                + useDeprKind.anno
+                + "class Class { "
+                + refKind.getFragment(declDeprKind)
+                + " }";
+    }
+
+    private static final String NO_OUTPUT = null;
+
+    public Removal() throws IOException {
+        super(System.err);
+        initLib();
+    }
+
+    void initLib() throws IOException {
+        tb.writeJavaFiles(libSrc, lib);
+
+        new JavacTask(tb)
+                .outdir(Files.createDirectories(libClasses))
+                .files(tb.findJavaFiles(libSrc))
+                .run()
+                .writeAll();
+    }
+
+    void report() {
+        out.println(testCount + " test cases");
+    }
+
+    /*
+     * Declaration site: not deprecated; use site: not deprecated
+     * Options: default
+     * Expect: no warnings
+     */
+    @Test
+    public void test_DeclNone_UseNone(Path base) throws IOException {
+        for (RefKind rk : RefKind.values()) {
+            test(base,
+                    getSource(rk, DeprKind.NONE, DeprKind.NONE),
+                    Options.DEFAULT,
+                    NO_OUTPUT);
+        }
+    }
+
+    /*
+     * Declaration site: not deprecated; use site: deprecated
+     * Options: default
+     * Expect: no warnings
+     */
+    @Test
+    public void test_DeclNone_UseDeprecated(Path base) throws IOException {
+        for (RefKind rk : RefKind.values()) {
+            test(base,
+                    getSource(rk, DeprKind.NONE, DeprKind.DEPRECATED),
+                    Options.DEFAULT,
+                    NO_OUTPUT);
+        }
+    }
+
+    /*
+     * Declaration site: not deprecated; use site: deprecated for removal
+     * Options: default
+     * Expect: no warnings
+     */
+    @Test
+    public void test_DeclNone_UseRemoval(Path base) throws IOException {
+        for (RefKind rk : RefKind.values()) {
+            test(base,
+                    getSource(rk, DeprKind.NONE, DeprKind.REMOVAL),
+                    Options.DEFAULT,
+                    NO_OUTPUT);
+        }
+    }
+
+    /*
+     * Declaration site: deprecated; use site: not deprecated
+     * Options: default
+     * Expect: deprecated note
+     */
+    @Test
+    public void test_DeclDeprecated_UseNone_Default(Path base) throws IOException {
+        for (RefKind rk : RefKind.values()) {
+            test(base,
+                    getSource(rk, DeprKind.DEPRECATED, DeprKind.NONE),
+                    Options.DEFAULT,
+                    "compiler.note.deprecated.filename: Class.java");
+        }
+    }
+
+    /*
+     * Declaration site: deprecated; use site: not deprecated
+     * Options: -Xlint:deprecation
+     * Expect: deprecated warning
+     */
+    @Test
+    public void test_DeclDeprecated_UseNone_XlintDep(Path base) throws IOException {
+        for (RefKind rk : RefKind.values()) {
+            String error = "<unset>";
+            switch (rk) {
+                case CLASS:
+                    error = "Class.java:1:29: compiler.warn.has.been.deprecated: lib.DepClass, lib";
+                    break;
+
+                case METHOD:
+                    error = "Class.java:1:37: compiler.warn.has.been.deprecated: depMethod(), lib.Class";
+                    break;
+
+                case FIELD:
+                    error = "Class.java:1:43: compiler.warn.has.been.deprecated: depField, lib.Class";
+                    break;
+            }
+
+            test(base,
+                    getSource(rk, DeprKind.DEPRECATED, DeprKind.NONE),
+                    Options.XLINT_DEPRECATED,
+                    error);
+        }
+    }
+
+    /*
+     * Declaration site: deprecated; use site: deprecated
+     * Options: default
+     * Expect: no warnings
+     */
+    @Test
+    public void test_DeclDeprecated_UseDeprecated(Path base) throws IOException {
+        for (RefKind rk : RefKind.values()) {
+            test(base,
+                    getSource(rk, DeprKind.DEPRECATED, DeprKind.DEPRECATED),
+                    Options.DEFAULT,
+                    NO_OUTPUT);
+        }
+    }
+
+    /*
+     * Declaration site: deprecated; use site: deprecated for removal
+     * Options: default
+     * Expect: no warnings
+     */
+    @Test
+    public void test_DeclDeprecated_UseRemoval(Path base) throws IOException {
+        for (RefKind rk : RefKind.values()) {
+            test(base,
+                    getSource(rk, DeprKind.DEPRECATED, DeprKind.REMOVAL),
+                    Options.DEFAULT,
+                    NO_OUTPUT);
+        }
+    }
+
+    /*
+     * Declaration site: deprecated for removal; use site: not deprecated
+     * Options: default
+     * Expect: removal warning
+     */
+    @Test
+    public void test_DeclRemoval_UseNone_Default(Path base) throws IOException {
+        for (RefKind rk : RefKind.values()) {
+            String error = "<unset>";
+            switch (rk) {
+                case CLASS:
+                    error = "Class.java:1:29: compiler.warn.has.been.deprecated.for.removal: lib.RemClass, lib";
+                    break;
+
+                case METHOD:
+                    error = "Class.java:1:37: compiler.warn.has.been.deprecated.for.removal: remMethod(), lib.Class";
+                    break;
+
+                case FIELD:
+                    error = "Class.java:1:43: compiler.warn.has.been.deprecated.for.removal: remField, lib.Class";
+                    break;
+            }
+
+            test(base,
+                    getSource(rk, DeprKind.REMOVAL, DeprKind.NONE),
+                    Options.DEFAULT,
+                    error);
+        }
+    }
+
+    /*
+     * Declaration site: deprecated for removal; use site: not deprecated
+     * Options: default, @SuppressWarnings("removal")
+     * Expect: removal warning
+     */
+    @Test
+    public void test_DeclRemoval_UseNone_SuppressRemoval(Path base) throws IOException {
+        for (RefKind rk : RefKind.values()) {
+            String source =
+                    getSource(rk, DeprKind.REMOVAL, DeprKind.NONE)
+                    .replace("class Class", "@SuppressWarnings(\"removal\") class Class");
+
+            test(base,
+                    source,
+                    Options.DEFAULT,
+                    null);
+        }
+    }
+
+    /*
+     * Declaration site: deprecated for removal; use site: not deprecated
+     * Options: -Xlint:-removal
+     * Expect: removal note
+     */
+    @Test
+    public void test_DeclRemoval_UseNone_XlintNoRemoval(Path base) throws IOException {
+        for (RefKind rk : RefKind.values()) {
+            test(base,
+                    getSource(rk, DeprKind.REMOVAL, DeprKind.NONE),
+                    Options.XLINT_NO_REMOVAL,
+                    "compiler.note.removal.filename: Class.java");
+        }
+    }
+
+    /*
+     * Declaration site: deprecated for removal; use site: deprecated
+     * Options: default
+     * Expect: removal warning
+     */
+    @Test
+    public void test_DeclRemoval_UseDeprecated_Default(Path base) throws IOException {
+        for (RefKind rk : RefKind.values()) {
+            String error = "<unset>";
+            switch (rk) {
+                case CLASS:
+                    error = "Class.java:1:41: compiler.warn.has.been.deprecated.for.removal: lib.RemClass, lib";
+                    break;
+
+                case METHOD:
+                    error = "Class.java:1:49: compiler.warn.has.been.deprecated.for.removal: remMethod(), lib.Class";
+                    break;
+
+                case FIELD:
+                    error = "Class.java:1:55: compiler.warn.has.been.deprecated.for.removal: remField, lib.Class";
+                    break;
+            }
+
+            test(base,
+                    getSource(rk, DeprKind.REMOVAL, DeprKind.DEPRECATED),
+                    Options.DEFAULT,
+                    error);
+        }
+    }
+
+    /*
+     * Declaration site: deprecated for removal; use site: deprecated
+     * Options: -Xlint:-removal
+     * Expect: removal note
+     */
+    @Test
+    public void test_DeclRemoval_UseDeprecated_XlintNoRemoval(Path base) throws IOException {
+        for (RefKind rk : RefKind.values()) {
+            test(base,
+                    getSource(rk, DeprKind.REMOVAL, DeprKind.DEPRECATED),
+                    Options.XLINT_NO_REMOVAL,
+                    "compiler.note.removal.filename: Class.java");
+        }
+    }
+
+    /*
+     * Declaration site: deprecated for removal; use site: deprecated for removal
+     * Options: default
+     * Expect: removal warning
+     */
+    @Test
+    public void test_DeclRemoval_UseRemoval_Default(Path base) throws IOException {
+        for (RefKind rk : RefKind.values()) {
+            String error = "<unset>";
+            switch (rk) {
+                case CLASS:
+                    error = "Class.java:1:58: compiler.warn.has.been.deprecated.for.removal: lib.RemClass, lib";
+                    break;
+
+                case METHOD:
+                    error = "Class.java:1:66: compiler.warn.has.been.deprecated.for.removal: remMethod(), lib.Class";
+                    break;
+
+                case FIELD:
+                    error = "Class.java:1:72: compiler.warn.has.been.deprecated.for.removal: remField, lib.Class";
+                    break;
+            }
+
+            test(base,
+                    getSource(rk, DeprKind.REMOVAL, DeprKind.REMOVAL),
+                    Options.DEFAULT,
+                    error);
+        }
+    }
+
+    /*
+     * Declaration site: deprecated for removal; use site: deprecated for removal
+     * Options: -Xlint:-removal
+     * Expect: removal note
+     */
+    @Test
+    public void test_DeclRemoval_UseRemoval_XlintNoRemoval(Path base) throws IOException {
+        for (RefKind rk : RefKind.values()) {
+            test(base,
+                    getSource(rk, DeprKind.REMOVAL, DeprKind.REMOVAL),
+                    Options.XLINT_NO_REMOVAL,
+                    "compiler.note.removal.filename: Class.java");
+        }
+    }
+
+    /*
+     * Additional special case:
+     * there should not be any warnings for any reference in a type-import statement.
+     */
+    @Test
+    public void test_UseImports(Path base) throws IOException {
+        String source =
+                "import lib.Class;\n"
+                + "import lib.DepClass;\n"
+                + "import lib.RemClass;\n"
+                + "class C { }";
+        for (Options o : Options.values()) {
+            test(base, source, o, NO_OUTPUT);
+        }
+    }
+
+    /**
+     * Compile source code with given options, and check for expected output.
+     * The compilation is done twice, first against the library in source form,
+     * and then again, against the compiled library.
+     * @param base base working directory
+     * @param source the source code to be compiled
+     * @param options the options for the compilation
+     * @param expectText the expected output, or NO_OUTPUT, if none expected.
+     * @throws IOException if an error occurs during the compilation
+     */
+    private void test(Path base, String source, Options options, String expectText) throws IOException {
+        test(base.resolve("lib-source"), libSrc, source, options, expectText);
+        test(base.resolve("lib-classes"), libClasses, source, options, expectText);
+    }
+
+    /**
+     * Compile source code with given options against a given version of the library,
+     * and check for expected output.
+     * @param base base working directory
+     * @param lib the directory containing the library, in either source or compiled form
+     * @param source the source code to be compiled
+     * @param options the options for the compilation
+     * @param expectText the expected output, or NO_OUTPUT, if none expected.
+     * @throws IOException if an error occurs during the compilation
+     */
+    private void test(Path base, Path lib, String source, Options options, String expectText)
+            throws IOException {
+        Expect expect = (expectText != null && expectText.contains("compiler.warn.")) ? Expect.FAIL : Expect.SUCCESS;
+        test(base, lib, source, options.opts, expect, expectText);
+    }
+
+    /**
+     * Compile source code with given options against a given version of the library,
+     * and check for expected exit code and expected output.
+     * @param base base working directory
+     * @param lib the directory containing the library, in either source or compiled form
+     * @param source the source code to be compiled
+     * @param options the options for the compilation
+     * @param expect the expected outcome of the compilation
+     * @param expectText the expected output, or NO_OUTPUT, if none expected.
+     * @throws IOException if an error occurs during the compilation
+     */
+    private void test(Path base, Path lib, String source, List<String> options,
+            Expect expect, String expectText) throws IOException {
+        testCount++;
+
+        Path src = base.resolve("src");
+        Path classes = Files.createDirectories(base.resolve("classes"));
+        tb.writeJavaFiles(src, source);
+
+        List<String> allOptions = new ArrayList<>();
+        allOptions.add("-XDrawDiagnostics");
+        allOptions.add("-Werror");
+        allOptions.addAll(options);
+
+        out.println("Source: " + source);
+        out.println("Classpath: " + lib);
+        out.println("Options: " + options.stream().collect(Collectors.joining(" ")));
+
+        String log = new JavacTask(tb)
+                .outdir(classes)
+                .classpath(lib) // use classpath for libSrc or libClasses
+                .files(tb.findJavaFiles(src))
+                .options(allOptions.toArray(new String[0]))
+                .run(expect)
+                .writeAll()
+                .getOutput(OutputKind.DIRECT);
+
+        if (expectText == null) {
+            if (!log.trim().isEmpty())
+                error("Unexpected text found: >>>" + log + "<<<");
+        } else {
+            if (!log.contains(expectText))
+                error("expected text not found: >>>" + expectText + "<<<");
+        }
+    }
+}
+