1 /* 2 * Copyright (c) 2018, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.javac.code; 27 28 import com.sun.tools.javac.code.Lint.LintCategory; 29 import com.sun.tools.javac.code.Source.Feature; 30 import com.sun.tools.javac.jvm.Target; 31 import com.sun.tools.javac.resources.CompilerProperties.Errors; 32 import com.sun.tools.javac.resources.CompilerProperties.Warnings; 33 import com.sun.tools.javac.util.Assert; 34 import com.sun.tools.javac.util.Context; 35 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 36 import com.sun.tools.javac.util.JCDiagnostic.Error; 37 import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition; 38 import com.sun.tools.javac.util.JCDiagnostic.Warning; 39 import com.sun.tools.javac.util.Log; 40 import com.sun.tools.javac.util.MandatoryWarningHandler; 41 import com.sun.tools.javac.util.Options; 42 43 import javax.tools.JavaFileObject; 44 import java.util.HashMap; 45 import java.util.Map; 46 47 import static com.sun.tools.javac.main.Option.PREVIEW; 48 49 /** 50 * Helper class to handle preview language features. This class maps certain language features 51 * (see {@link Feature} into 'preview' features; the mapping is completely ad-hoc, so as to allow 52 * for maximum flexibility, which allows to migrate preview feature into supported features with ease. 53 * 54 * This class acts as a centralized point against which usages of preview features are reported by 55 * clients (e.g. other javac classes). Internally, this class collects all such usages and generates 56 * diagnostics to inform the user of such usages. Such diagnostics can be enabled using the 57 * {@link LintCategory#PREVIEW} lint category, and are suppressible by usual means. 58 */ 59 public class Preview { 60 61 /** flag: are preview features enabled */ 62 private final boolean enabled; 63 64 /** the diag handler to manage preview feature usage diagnostics */ 65 private final MandatoryWarningHandler previewHandler; 66 67 /** test flag: should all features be considered as preview features? */ 68 private final boolean forcePreview; 69 70 /** a mapping from classfile numbers to Java SE versions */ 71 private final Map<Integer, Source> majorVersionToSource; 72 73 74 private final Lint lint; 75 private final Log log; 76 77 private static final Context.Key<Preview> previewKey = new Context.Key<>(); 78 79 public static Preview instance(Context context) { 80 Preview instance = context.get(previewKey); 81 if (instance == null) { 82 instance = new Preview(context); 83 } 84 return instance; 85 } 86 87 Preview(Context context) { 88 context.put(previewKey, this); 89 Options options = Options.instance(context); 90 enabled = options.isSet(PREVIEW); 91 log = Log.instance(context); 92 lint = Lint.instance(context); 93 this.previewHandler = 94 new MandatoryWarningHandler(log, lint.isEnabled(LintCategory.PREVIEW), true, "preview", LintCategory.PREVIEW); 95 forcePreview = options.isSet("forcePreview"); 96 majorVersionToSource = initMajorVersionToSourceMap(); 97 } 98 99 private Map<Integer, Source> initMajorVersionToSourceMap() { 100 Map<Integer, Source> majorVersionToSource = new HashMap<>(); 101 for (Target t : Target.values()) { 102 int major = t.majorVersion; 103 Source source = Source.lookup(t.name); 104 if (source != null) { 105 majorVersionToSource.put(major, source); 106 } 107 } 108 return majorVersionToSource; 109 } 110 111 /** 112 * Report usage of a preview feature. Usages reported through this method will affect the 113 * set of sourcefiles with dependencies on preview features. 114 * @param pos the position at which the preview feature was used. 115 * @param feature the preview feature used. 116 */ 117 public void warnPreview(int pos, Feature feature) { 118 warnPreview(new SimpleDiagnosticPosition(pos), feature); 119 } 120 121 /** 122 * Report usage of a preview feature. Usages reported through this method will affect the 123 * set of sourcefiles with dependencies on preview features. 124 * @param pos the position at which the preview feature was used. 125 * @param feature the preview feature used. 126 */ 127 public void warnPreview(DiagnosticPosition pos, Feature feature) { 128 Assert.check(isEnabled()); 129 Assert.check(isPreview(feature)); 130 if (!lint.isSuppressed(LintCategory.PREVIEW)) { 131 previewHandler.report(pos, feature.isPlural() ? 132 Warnings.PreviewFeatureUsePlural(feature.nameFragment()) : 133 Warnings.PreviewFeatureUse(feature.nameFragment())); 134 } 135 } 136 137 /** 138 * Report usage of a preview feature in classfile. 139 * @param classfile the name of the classfile with preview features enabled 140 * @param majorVersion the major version found in the classfile. 141 */ 142 public void warnPreview(JavaFileObject classfile, int majorVersion) { 143 Assert.check(isEnabled()); 144 if (!lint.isSuppressed(LintCategory.PREVIEW)) { 145 previewHandler.report(null, 146 Warnings.PreviewFeatureUseClassfile(classfile, majorVersionToSource.get(majorVersion).name)); 147 } 148 } 149 150 public void reportPreviewWarning(DiagnosticPosition pos, Warning warnKey) { 151 previewHandler.report(pos, warnKey); 152 } 153 154 /** 155 * Are preview features enabled? 156 * @return true, if preview features are enabled. 157 */ 158 public boolean isEnabled() { 159 return enabled; 160 } 161 162 /** 163 * Is given feature a preview feature? 164 * @param feature the feature to be tested. 165 * @return true, if given feature is a preview feature. 166 */ 167 public boolean isPreview(Feature feature) { 168 if (feature == Feature.SWITCH_EXPRESSION || 169 feature == Feature.SWITCH_MULTIPLE_CASE_LABELS || 170 feature == Feature.SWITCH_RULE || 171 feature == Feature.TEXT_BLOCKS) 172 return true; 173 //Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing). 174 //When real preview features will be added, this method can be implemented to return 'true' 175 //for those selected features, and 'false' for all the others. 176 return forcePreview; 177 } 178 179 /** 180 * Generate an error key which captures the fact that a given preview feature could not be used 181 * due to the preview feature support being disabled. 182 * @param feature the feature for which the diagnostic has to be generated. 183 * @return the diagnostic. 184 */ 185 public Error disabledError(Feature feature) { 186 Assert.check(!isEnabled()); 187 return feature.isPlural() ? 188 Errors.PreviewFeatureDisabledPlural(feature.nameFragment()) : 189 Errors.PreviewFeatureDisabled(feature.nameFragment()); 190 } 191 192 /** 193 * Generate an error key which captures the fact that a preview classfile cannot be loaded 194 * due to the preview feature support being disabled. 195 * @param classfile the name of the classfile with preview features enabled 196 * @param majorVersion the major version found in the classfile. 197 */ 198 public Error disabledError(JavaFileObject classfile, int majorVersion) { 199 Assert.check(!isEnabled()); 200 return Errors.PreviewFeatureDisabledClassfile(classfile, majorVersionToSource.get(majorVersion).name); 201 } 202 203 /** 204 * Report any deferred diagnostics. 205 */ 206 public void reportDeferredDiagnostics() { 207 previewHandler.reportDeferredDiagnostic(); 208 } 209 210 public void clear() { 211 previewHandler.clear(); 212 } 213 214 }