001 /* 002 * Copyright 2005-2008 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.code; 027 028 import java.util.EnumSet; 029 import java.util.HashMap; 030 import java.util.Map; 031 import com.sun.tools.javac.code.Symbol.*; 032 import com.sun.tools.javac.util.Context; 033 import com.sun.tools.javac.util.List; 034 import com.sun.tools.javac.util.Options; 035 import com.sun.tools.javac.util.Pair; 036 import static com.sun.tools.javac.code.Flags.*; 037 038 039 /** 040 * A class for handling -Xlint suboptions and @SuppresssWarnings. 041 * 042 * <p><b>This is NOT part of any API supported by Sun Microsystems. If 043 * you write code that depends on this, you do so at your own risk. 044 * This code and its internal interfaces are subject to change or 045 * deletion without notice.</b> 046 */ 047 public class Lint 048 { 049 /** The context key for the root Lint object. */ 050 protected static final Context.Key<Lint> lintKey = new Context.Key<Lint>(); 051 052 /** Get the root Lint instance. */ 053 public static Lint instance(Context context) { 054 Lint instance = context.get(lintKey); 055 if (instance == null) 056 instance = new Lint(context); 057 return instance; 058 } 059 060 /** 061 * Returns the result of combining the values in this object with 062 * the given annotation. 063 */ 064 public Lint augment(Attribute.Compound attr) { 065 return augmentor.augment(this, attr); 066 } 067 068 069 /** 070 * Returns the result of combining the values in this object with 071 * the given annotations. 072 */ 073 public Lint augment(List<Attribute.Compound> attrs) { 074 return augmentor.augment(this, attrs); 075 } 076 077 /** 078 * Returns the result of combining the values in this object with 079 * the given annotations and flags. 080 */ 081 public Lint augment(List<Attribute.Compound> attrs, long flags) { 082 Lint l = augmentor.augment(this, attrs); 083 if ((flags & DEPRECATED) != 0) { 084 if (l == this) 085 l = new Lint(this); 086 l.values.remove(LintCategory.DEPRECATION); 087 l.suppressedValues.add(LintCategory.DEPRECATION); 088 } 089 return l; 090 } 091 092 093 private final AugmentVisitor augmentor; 094 095 private final EnumSet<LintCategory> values; 096 private final EnumSet<LintCategory> suppressedValues; 097 098 private static Map<String, LintCategory> map = new HashMap<String,LintCategory>(); 099 100 101 protected Lint(Context context) { 102 // initialize values according to the lint options 103 Options options = Options.instance(context); 104 values = EnumSet.noneOf(LintCategory.class); 105 for (Map.Entry<String, LintCategory> e: map.entrySet()) { 106 if (options.lint(e.getKey())) 107 values.add(e.getValue()); 108 } 109 110 suppressedValues = EnumSet.noneOf(LintCategory.class); 111 112 context.put(lintKey, this); 113 augmentor = new AugmentVisitor(context); 114 } 115 116 protected Lint(Lint other) { 117 this.augmentor = other.augmentor; 118 this.values = other.values.clone(); 119 this.suppressedValues = other.suppressedValues.clone(); 120 } 121 122 public String toString() { 123 return "Lint:[values" + values + " suppressedValues" + suppressedValues + "]"; 124 } 125 126 /** 127 * Categories of warnings that can be generated by the compiler. 128 */ 129 public enum LintCategory { 130 /** 131 * Warn about use of unnecessary casts. 132 */ 133 CAST("cast"), 134 135 /** 136 * Warn about use of deprecated items. 137 */ 138 DEPRECATION("deprecation"), 139 140 /** 141 * Warn about items which are documented with an {@code @deprecated} JavaDoc 142 * comment, but which do not have {@code @Deprecated} annotation. 143 */ 144 DEP_ANN("dep-ann"), 145 146 /** 147 * Warn about division by constant integer 0. 148 */ 149 DIVZERO("divzero"), 150 151 /** 152 * Warn about empty statement after if. 153 */ 154 EMPTY("empty"), 155 156 /** 157 * Warn about falling through from one case of a switch statement to the next. 158 */ 159 FALLTHROUGH("fallthrough"), 160 161 /** 162 * Warn about finally clauses that do not terminate normally. 163 */ 164 FINALLY("finally"), 165 166 /** 167 * Warn about issues regarding method overrides. 168 */ 169 OVERRIDES("overrides"), 170 171 /** 172 * Warn about invalid path elements on the command line. 173 * Such warnings cannot be suppressed with the SuppressWarnings 174 * annotation. 175 */ 176 PATH("path"), 177 178 /** 179 * Warn about issues regarding annotation processing. 180 */ 181 PROCESSING("processing"), 182 183 /** 184 * Warn about Serializable classes that do not provide a serial version ID. 185 */ 186 SERIAL("serial"), 187 188 /** 189 * Warn about unchecked operations on raw types. 190 */ 191 UNCHECKED("unchecked"), 192 193 /** 194 * Warn about unchecked operations on raw types. 195 */ 196 RAW("rawtypes"); 197 198 LintCategory(String option) { 199 this.option = option; 200 map.put(option, this); 201 } 202 203 static LintCategory get(String option) { 204 return map.get(option); 205 } 206 207 public final String option; 208 }; 209 210 /** 211 * Checks if a warning category is enabled. A warning category may be enabled 212 * on the command line, or by default, and can be temporarily disabled with 213 * the SuppressWarnings annotation. 214 */ 215 public boolean isEnabled(LintCategory lc) { 216 return values.contains(lc); 217 } 218 219 /** 220 * Checks is a warning category has been specifically suppressed, by means 221 * of the SuppressWarnings annotation, or, in the case of the deprecated 222 * category, whether it has been implicitly suppressed by virtue of the 223 * current entity being itself deprecated. 224 */ 225 public boolean isSuppressed(LintCategory lc) { 226 return suppressedValues.contains(lc); 227 } 228 229 protected static class AugmentVisitor implements Attribute.Visitor { 230 private final Context context; 231 private Symtab syms; 232 private Lint parent; 233 private Lint lint; 234 235 AugmentVisitor(Context context) { 236 // to break an ugly sequence of initialization dependencies, 237 // we defer the initialization of syms until it is needed 238 this.context = context; 239 } 240 241 Lint augment(Lint parent, Attribute.Compound attr) { 242 initSyms(); 243 this.parent = parent; 244 lint = null; 245 attr.accept(this); 246 return (lint == null ? parent : lint); 247 } 248 249 Lint augment(Lint parent, List<Attribute.Compound> attrs) { 250 initSyms(); 251 this.parent = parent; 252 lint = null; 253 for (Attribute.Compound a: attrs) { 254 a.accept(this); 255 } 256 return (lint == null ? parent : lint); 257 } 258 259 private void initSyms() { 260 if (syms == null) 261 syms = Symtab.instance(context); 262 } 263 264 private void suppress(LintCategory lc) { 265 if (lint == null) 266 lint = new Lint(parent); 267 lint.suppressedValues.add(lc); 268 lint.values.remove(lc); 269 } 270 271 public void visitConstant(Attribute.Constant value) { 272 if (value.type.tsym == syms.stringType.tsym) { 273 LintCategory lc = LintCategory.get((String) (value.value)); 274 if (lc != null) 275 suppress(lc); 276 } 277 } 278 279 public void visitClass(Attribute.Class clazz) { 280 } 281 282 // If we find a @SuppressWarnings annotation, then we continue 283 // walking the tree, in order to suppress the individual warnings 284 // specified in the @SuppressWarnings annotation. 285 public void visitCompound(Attribute.Compound compound) { 286 if (compound.type.tsym == syms.suppressWarningsType.tsym) { 287 for (List<Pair<MethodSymbol,Attribute>> v = compound.values; 288 v.nonEmpty(); v = v.tail) { 289 Pair<MethodSymbol,Attribute> value = v.head; 290 if (value.fst.name.toString().equals("value")) 291 value.snd.accept(this); 292 } 293 294 } 295 } 296 297 public void visitArray(Attribute.Array array) { 298 for (Attribute value : array.values) 299 value.accept(this); 300 } 301 302 public void visitEnum(Attribute.Enum e) { 303 } 304 305 public void visitError(Attribute.Error e) { 306 } 307 }; 308 }