001: /*
002: * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.javac.util;
027:
028: import java.util.HashSet;
029: import java.util.Set;
030: import javax.tools.JavaFileObject;
031:
032: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
033:
034: /**
035: * A handler to process mandatory warnings, setting up a deferred diagnostic
036: * to be printed at the end of the compilation if some warnings get suppressed
037: * because too many warnings have already been generated.
038: *
039: * Note that the SuppressWarnings annotation can be used to suppress warnings
040: * about conditions that would otherwise merit a warning. Such processing
041: * is done when the condition is detected, and in those cases, no call is
042: * made on any API to generate a warning at all. In consequence, this handler only
043: * gets to handle those warnings that JLS says must be generated.
044: *
045: * <p><b>This is NOT part of any API supported by Sun Microsystems. If
046: * you write code that depends on this, you do so at your own risk.
047: * This code and its internal interfaces are subject to change or
048: * deletion without notice.</b>
049: */
050: @Version("@(#)MandatoryWarningHandler.java 1.15 07/05/05")
051: public class MandatoryWarningHandler {
052:
053: /**
054: * The kinds of different deferred diagnostics that might be generated
055: * if a mandatory warning is suppressed because too many warnings have
056: * already been output.
057: *
058: * The parameter is a fragment used to build an I18N message key for Log.
059: */
060: private enum DeferredDiagnosticKind {
061: /**
062: * This kind is used when a single specific file is found to have warnings
063: * and no similar warnings have already been given.
064: * It generates a message like:
065: * FILE has ISSUES
066: */
067: IN_FILE(".filename"),
068: /**
069: * This kind is used when a single specific file is found to have warnings
070: * and when similar warnings have already been reported for the file.
071: * It generates a message like:
072: * FILE has additional ISSUES
073: */
074: ADDITIONAL_IN_FILE(".filename.additional"),
075: /**
076: * This kind is used when multiple files have been found to have warnings,
077: * and none of them have had any similar warnings.
078: * It generates a message like:
079: * Some files have ISSUES
080: */
081: IN_FILES(".plural"),
082: /**
083: * This kind is used when multiple files have been found to have warnings,
084: * and some of them have had already had specific similar warnings.
085: * It generates a message like:
086: * Some files have additional ISSUES
087: */
088: ADDITIONAL_IN_FILES(".plural.additional");
089:
090: DeferredDiagnosticKind(String v) {
091: value = v;
092: }
093:
094: String getKey(String prefix) {
095: return prefix + value;
096: }
097:
098: private String value;
099: }
100:
101: /**
102: * Create a handler for mandatory warnings.
103: * @param log The log on which to generate any diagnostics
104: * @param verbose Specify whether or not detailed messages about
105: * individual instances should be given, or whether an aggregate
106: * message should be generated at the end of the compilation.
107: * Typically set via -Xlint:option.
108: * @param prefix A common prefix for the set of message keys for
109: * the messages that may be generated.
110: */
111: public MandatoryWarningHandler(Log log, boolean verbose,
112: String prefix) {
113: this .log = log;
114: this .verbose = verbose;
115: this .prefix = prefix;
116: }
117:
118: /**
119: * Report a mandatory warning.
120: */
121: public void report(DiagnosticPosition pos, String msg,
122: Object... args) {
123: JavaFileObject currentSource = log.currentSource();
124:
125: if (verbose) {
126: if (sourcesWithReportedWarnings == null)
127: sourcesWithReportedWarnings = new HashSet<JavaFileObject>();
128:
129: if (log.nwarnings < log.MaxWarnings) {
130: // generate message and remember the source file
131: log.mandatoryWarning(pos, msg, args);
132: sourcesWithReportedWarnings.add(currentSource);
133: } else if (deferredDiagnosticKind == null) {
134: // set up deferred message
135: if (sourcesWithReportedWarnings.contains(currentSource)) {
136: // more errors in a file that already has reported warnings
137: deferredDiagnosticKind = DeferredDiagnosticKind.ADDITIONAL_IN_FILE;
138: } else {
139: // warnings in a new source file
140: deferredDiagnosticKind = DeferredDiagnosticKind.IN_FILE;
141: }
142: deferredDiagnosticSource = currentSource;
143: deferredDiagnosticArg = currentSource;
144: } else if ((deferredDiagnosticKind == DeferredDiagnosticKind.IN_FILE || deferredDiagnosticKind == DeferredDiagnosticKind.ADDITIONAL_IN_FILE)
145: && !equal(deferredDiagnosticSource, currentSource)) {
146: // additional errors in more than one source file
147: deferredDiagnosticKind = DeferredDiagnosticKind.ADDITIONAL_IN_FILES;
148: deferredDiagnosticArg = null;
149: }
150: } else {
151: if (deferredDiagnosticKind == null) {
152: // warnings in a single source
153: deferredDiagnosticKind = DeferredDiagnosticKind.IN_FILE;
154: deferredDiagnosticSource = currentSource;
155: deferredDiagnosticArg = currentSource;
156: } else if (deferredDiagnosticKind == DeferredDiagnosticKind.IN_FILE
157: && !equal(deferredDiagnosticSource, currentSource)) {
158: // warnings in multiple source files
159: deferredDiagnosticKind = DeferredDiagnosticKind.IN_FILES;
160: deferredDiagnosticArg = null;
161: }
162: }
163: }
164:
165: /**
166: * Report any diagnostic that might have been deferred by previous calls of report().
167: */
168: public void reportDeferredDiagnostic() {
169: if (deferredDiagnosticKind != null) {
170: if (deferredDiagnosticArg == null)
171: log.mandatoryNote(deferredDiagnosticSource,
172: deferredDiagnosticKind.getKey(prefix));
173: else
174: log.mandatoryNote(deferredDiagnosticSource,
175: deferredDiagnosticKind.getKey(prefix),
176: deferredDiagnosticArg);
177:
178: if (!verbose)
179: log.mandatoryNote(deferredDiagnosticSource, prefix
180: + ".recompile");
181: }
182: }
183:
184: /**
185: * Check two objects, each possibly null, are either both null or are equal.
186: */
187: private static boolean equal(Object o1, Object o2) {
188: return ((o1 == null || o2 == null) ? (o1 == o2) : o1.equals(o2));
189: }
190:
191: /**
192: * The log to which to report warnings.
193: */
194: private Log log;
195:
196: /**
197: * Whether or not to report individual warnings, or simply to report a
198: * single aggregate warning at the end of the compilation.
199: */
200: private boolean verbose;
201:
202: /**
203: * The common prefix for all I18N message keys generated by this handler.
204: */
205: private String prefix;
206:
207: /**
208: * A set containing the names of the source files for which specific
209: * warnings have been generated -- i.e. in verbose mode. If a source name
210: * appears in this list, then deferred diagnostics will be phrased to
211: * include "additionally"...
212: */
213: private Set<JavaFileObject> sourcesWithReportedWarnings;
214:
215: /**
216: * A variable indicating the latest best guess at what the final
217: * deferred diagnostic will be. Initially as specific and helpful
218: * as possible, as more warnings are reported, the scope of the
219: * diagnostic will be broadened.
220: */
221: private DeferredDiagnosticKind deferredDiagnosticKind;
222:
223: /**
224: * If deferredDiagnosticKind is IN_FILE or ADDITIONAL_IN_FILE, this variable
225: * gives the value of log.currentSource() for the file in question.
226: */
227: private JavaFileObject deferredDiagnosticSource;
228:
229: /**
230: * An optional argument to be used when constructing the
231: * deferred diagnostic message, based on deferredDiagnosticKind.
232: * This variable should normally be set/updated whenever
233: * deferredDiagnosticKind is updated.
234: */
235: private Object deferredDiagnosticArg;
236: }
|