/* * FindBugs - Find bugs in Java programs * Copyright (C) 2003-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; import java.io.IOException; import edu.umd.cs.findbugs.ba.AnalysisContext; import edu.umd.cs.findbugs.ba.SourceInfoMap; import edu.umd.cs.findbugs.classfile.ClassDescriptor; import edu.umd.cs.findbugs.internalAnnotations.DottedClassName; import edu.umd.cs.findbugs.util.ClassName; import edu.umd.cs.findbugs.xml.XMLAttributeList; import edu.umd.cs.findbugs.xml.XMLOutput; /** * A BugAnnotation object specifying a Java class involved in the bug. * * @author David Hovemeyer * @see BugAnnotation * @see BugInstance */ public class ClassAnnotation extends PackageMemberAnnotation { private static final long serialVersionUID = 1L; private static final String DEFAULT_ROLE = "CLASS_DEFAULT"; public static final String SUBCLASS_ROLE = "CLASS_SUBCLASS"; public static final String SUPERCLASS_ROLE = "CLASS_SUPERCLASS"; public static final String RECOMMENDED_SUPERCLASS_ROLE = "CLASS_RECOMMENDED_SUPERCLASS"; public static final String IMPLEMENTED_INTERFACE_ROLE = "CLASS_IMPLEMENTED_INTERFACE"; public static final String INTERFACE_ROLE = "INTERFACE_TYPE"; public static final String ANNOTATION_ROLE = "CLASS_ANNOTATION"; public static final String TYPE_QUALIFIER_ROLE = "CLASS_TYPE_QUALIFIER"; /** * Constructor. * * @param className * the name of the class */ public ClassAnnotation(@DottedClassName String className) { super(className, DEFAULT_ROLE); } public ClassAnnotation(@DottedClassName String className, String sourceFileName) { super(className, DEFAULT_ROLE, sourceFileName); } @Override public boolean isSignificant() { return !SUBCLASS_ROLE.equals(description); } /** * Factory method to create a ClassAnnotation from a ClassDescriptor. * * @param classDescriptor * the ClassDescriptor * @return the ClassAnnotation */ public static ClassAnnotation fromClassDescriptor(ClassDescriptor classDescriptor) { return new ClassAnnotation(classDescriptor.toDottedClassName()); } public void accept(BugAnnotationVisitor visitor) { visitor.visitClassAnnotation(this); } @Override protected String formatPackageMember(String key, ClassAnnotation primaryClass) { if (key.equals("") || key.equals("hash")) return className; else if (key.equals("givenClass")) return shorten(primaryClass.getPackageName(), className); else if (key.equals("excludingPackage")) return shorten(getPackageName(), className); else if (key.equals("simpleClass") || key.equals("simpleName")) return ClassName.extractSimpleName(className); else throw new IllegalArgumentException("unknown key " + key); } @Override public int hashCode() { return className.hashCode(); } @Override public boolean equals(Object o) { if (!(o instanceof ClassAnnotation)) return false; ClassAnnotation other = (ClassAnnotation) o; return className.equals(other.className); } public boolean contains(ClassAnnotation other) { return other.className.startsWith(className); } public ClassAnnotation getTopLevelClass() { int firstDollar = className.indexOf('$'); if (firstDollar <= 0) return this; return new ClassAnnotation(className.substring(0, firstDollar)); } public int compareTo(BugAnnotation o) { if (!(o instanceof ClassAnnotation)) // BugAnnotations must be // Comparable with any type of // BugAnnotation return this.getClass().getName().compareTo(o.getClass().getName()); ClassAnnotation other = (ClassAnnotation) o; return className.compareTo(other.className); } /* * (non-Javadoc) * * @see edu.umd.cs.findbugs.PackageMemberAnnotation#getSourceLines() */ @Override public SourceLineAnnotation getSourceLines() { if (sourceLines == null) this.sourceLines = getSourceLinesForClass(className, sourceFileName); return sourceLines; } public static SourceLineAnnotation getSourceLinesForClass(@DottedClassName String className, String sourceFileName) { // Create source line annotation for class on demand AnalysisContext currentAnalysisContext = AnalysisContext.currentAnalysisContext(); if (currentAnalysisContext == null) return new SourceLineAnnotation(className, sourceFileName, -1, -1, -1, -1); SourceInfoMap.SourceLineRange classLine = currentAnalysisContext.getSourceInfoMap().getClassLine(className); if (classLine == null) return SourceLineAnnotation.getSourceAnnotationForClass(className, sourceFileName); else return new SourceLineAnnotation(className, sourceFileName, classLine.getStart(), classLine.getEnd(), -1, -1); } /* * ---------------------------------------------------------------------- * XML Conversion support * ---------------------------------------------------------------------- */ private static final String ELEMENT_NAME = "Class"; public void writeXML(XMLOutput xmlOutput) throws IOException { writeXML(xmlOutput, false, false); } public void writeXML(XMLOutput xmlOutput, boolean addMessages, boolean isPrimary) throws IOException { XMLAttributeList attributeList = new XMLAttributeList().addAttribute("classname", getClassName()); if (isPrimary) attributeList.addAttribute("primary", "true"); String role = getDescription(); if (!role.equals(DEFAULT_ROLE)) attributeList.addAttribute("role", role); xmlOutput.openTag(ELEMENT_NAME, attributeList); getSourceLines().writeXML(xmlOutput, addMessages, false); if (addMessages) { xmlOutput.openTag(BugAnnotation.MESSAGE_TAG); xmlOutput.writeText(this.toString()); xmlOutput.closeTag(BugAnnotation.MESSAGE_TAG); } xmlOutput.closeTag(ELEMENT_NAME); } } // vim:ts=4