/* * FindBugs - Find Bugs in Java programs * Copyright (C) 2005, University of Maryland * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package edu.umd.cs.findbugs.detect; import java.util.HashMap; import java.util.Map; import org.apache.bcel.classfile.ArrayElementValue; import org.apache.bcel.classfile.ClassElementValue; import org.apache.bcel.classfile.ElementValue; import edu.umd.cs.findbugs.SystemProperties; import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.ba.AnnotationDatabase; import edu.umd.cs.findbugs.ba.AnnotationDatabase.Target; import edu.umd.cs.findbugs.ba.NullnessAnnotation; import edu.umd.cs.findbugs.ba.NullnessAnnotationDatabase; import edu.umd.cs.findbugs.ba.XFactory; import edu.umd.cs.findbugs.ba.XMethod; import edu.umd.cs.findbugs.ba.XMethodParameter; import edu.umd.cs.findbugs.visitclass.AnnotationVisitor; /** * Scan application classes for NonNull annotations. * * @author David Hovemeyer * @author William Pugh */ public class BuildNonNullAnnotationDatabase extends AnnotationVisitor { private static final boolean DEBUG = SystemProperties.getBoolean("fnd.debug.annotation"); private static final String DEFAULT_ANNOTATION_ANNOTATION_CLASS = "DefaultAnnotation"; private static final Map<String, AnnotationDatabase.Target> defaultKind = new HashMap<String, AnnotationDatabase.Target>(); static { defaultKind.put("", AnnotationDatabase.Target.ANY); defaultKind.put("ForParameters", AnnotationDatabase.Target.PARAMETER); defaultKind.put("ForMethods", AnnotationDatabase.Target.METHOD); defaultKind.put("ForFields", AnnotationDatabase.Target.FIELD); } private NullnessAnnotationDatabase database; public BuildNonNullAnnotationDatabase(@CheckForNull NullnessAnnotationDatabase database) { this.database = database; } static String lastPortion(String className) { int i = className.lastIndexOf("."); if (i < 0) return className; return className.substring(i + 1); } /* * * @param value * * @param map * * @param annotationTarget */ private void handleClassElementValue(ClassElementValue value, Target annotationTarget) { NullnessAnnotation n = NullnessAnnotation.Parser.parse(value.getClassString()); if (n != null) database.addDefaultAnnotation(annotationTarget, getDottedClassName(), n); } @Override public void visitAnnotation(String annotationClass, Map<String, ElementValue> map, boolean runtimeVisible) { if (database == null) { return; } NullnessAnnotation n = NullnessAnnotation.Parser.parse(annotationClass); annotationClass = lastPortion(annotationClass); if (n == null) { if (annotationClass.startsWith("DefaultAnnotation")) { annotationClass = annotationClass.substring("DefaultAnnotation".length()); Target annotationTarget = defaultKind.get(annotationClass); if (annotationTarget != Target.METHOD) return; ElementValue v = map.get("value"); if (v instanceof ClassElementValue) { handleClassElementValue((ClassElementValue) v, annotationTarget); } else if (v instanceof ArrayElementValue) { for (ElementValue v2 : ((ArrayElementValue) v).getElementValuesArray()) { if (v2 instanceof ClassElementValue) handleClassElementValue((ClassElementValue) v2, annotationTarget); } } return; } } else if (visitingMethod()) database.addDirectAnnotation(XFactory.createXMethod(this), n); else if (visitingField()) database.addDirectAnnotation(XFactory.createXField(this), n); } @Override public void visitSyntheticParameterAnnotation(int p, boolean runtimeVisible) { if (database == null) { return; } XMethod xmethod = XFactory.createXMethod(this); XMethodParameter xparameter = new XMethodParameter(xmethod, p); database.addDirectAnnotation(xparameter, NullnessAnnotation.UNKNOWN_NULLNESS); } @Override public void visitParameterAnnotation(int p, String annotationClass, Map<String, ElementValue> map, boolean runtimeVisible) { if (database == null) { return; } NullnessAnnotation n = NullnessAnnotation.Parser.parse(annotationClass); annotationClass = lastPortion(annotationClass); if (n == null) return; XMethod xmethod = XFactory.createXMethod(this); if (DEBUG) { System.out.println("Parameter " + p + " @" + annotationClass.substring(annotationClass.lastIndexOf('/') + 1) + " in " + xmethod.toString()); } XMethodParameter xparameter = new XMethodParameter(xmethod, p); database.addDirectAnnotation(xparameter, n); } }