001: /*
002: * FindBugs - Find bugs in Java programs
003: * Copyright (C) 2003-2005, University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019:
020: package edu.umd.cs.findbugs;
021:
022: import java.io.IOException;
023:
024: import edu.umd.cs.findbugs.ba.AnalysisContext;
025: import edu.umd.cs.findbugs.ba.SourceInfoMap;
026: import edu.umd.cs.findbugs.classfile.ClassDescriptor;
027: import edu.umd.cs.findbugs.xml.XMLAttributeList;
028: import edu.umd.cs.findbugs.xml.XMLOutput;
029:
030: /**
031: * A BugAnnotation object specifying a Java class involved in the bug.
032: *
033: * @author David Hovemeyer
034: * @see BugAnnotation
035: * @see BugInstance
036: */
037: public class ClassAnnotation extends PackageMemberAnnotation {
038: private static final long serialVersionUID = 1L;
039:
040: private static final String DEFAULT_ROLE = "CLASS_DEFAULT";
041:
042: /**
043: * Constructor.
044: *
045: * @param className the name of the class
046: */
047: public ClassAnnotation(String className) {
048: super (className, DEFAULT_ROLE);
049: }
050:
051: /**
052: * Factory method to create a ClassAnnotation from a ClassDescriptor.
053: *
054: * @param classDescriptor the ClassDescriptor
055: * @return the ClassAnnotation
056: */
057: public static ClassAnnotation fromClassDescriptor(
058: ClassDescriptor classDescriptor) {
059: return new ClassAnnotation(classDescriptor.toDottedClassName());
060: }
061:
062: public void accept(BugAnnotationVisitor visitor) {
063: visitor.visitClassAnnotation(this );
064: }
065:
066: @Override
067: protected String formatPackageMember(String key,
068: ClassAnnotation primaryClass) {
069: if (key.equals("") || key.equals("hash"))
070: return className;
071: else if (key.equals("givenClass"))
072: return shorten(primaryClass.getPackageName(), className);
073: else if (key.equals("excludingPackage"))
074: return shorten(getPackageName(), className);
075: else
076: throw new IllegalArgumentException("unknown key " + key);
077: }
078:
079: @Override
080: public int hashCode() {
081: return className.hashCode();
082: }
083:
084: @Override
085: public boolean equals(Object o) {
086: if (!(o instanceof ClassAnnotation))
087: return false;
088: ClassAnnotation other = (ClassAnnotation) o;
089: return className.equals(other.className);
090: }
091:
092: public boolean contains(ClassAnnotation other) {
093: return other.className.startsWith(className);
094: }
095:
096: public ClassAnnotation getTopLevelClass() {
097: int firstDollar = className.indexOf('$');
098: if (firstDollar == -1)
099: return this ;
100: return new ClassAnnotation(className.substring(0, firstDollar));
101:
102: }
103:
104: public int compareTo(BugAnnotation o) {
105: if (!(o instanceof ClassAnnotation)) // BugAnnotations must be Comparable with any type of BugAnnotation
106: return this .getClass().getName().compareTo(
107: o.getClass().getName());
108: ClassAnnotation other = (ClassAnnotation) o;
109: return className.compareTo(other.className);
110: }
111:
112: /* (non-Javadoc)
113: * @see edu.umd.cs.findbugs.PackageMemberAnnotation#getSourceLines()
114: */
115: @Override
116: public SourceLineAnnotation getSourceLines() {
117: if (sourceLines == null) {
118: // Create source line annotation for class on demand
119:
120: AnalysisContext currentAnalysisContext = AnalysisContext
121: .currentAnalysisContext();
122: if (currentAnalysisContext == null)
123: sourceLines = new SourceLineAnnotation(className,
124: sourceFileName, -1, -1, -1, -1);
125: else {
126: SourceInfoMap.SourceLineRange classLine = currentAnalysisContext
127: .getSourceInfoMap().getClassLine(className);
128:
129: if (classLine == null)
130: sourceLines = SourceLineAnnotation
131: .getSourceAnnotationForClass(className,
132: sourceFileName);
133: else
134: sourceLines = new SourceLineAnnotation(className,
135: sourceFileName, classLine.getStart(),
136: classLine.getEnd(), -1, -1);
137: }
138: }
139: return sourceLines;
140: }
141:
142: /* ----------------------------------------------------------------------
143: * XML Conversion support
144: * ---------------------------------------------------------------------- */
145:
146: private static final String ELEMENT_NAME = "Class";
147:
148: public void writeXML(XMLOutput xmlOutput) throws IOException {
149: writeXML(xmlOutput, false);
150: }
151:
152: public void writeXML(XMLOutput xmlOutput, boolean addMessages)
153: throws IOException {
154: XMLAttributeList attributeList = new XMLAttributeList()
155: .addAttribute("classname", getClassName());
156: String role = getDescription();
157: if (!role.equals(DEFAULT_ROLE))
158: attributeList.addAttribute("role", role);
159:
160: xmlOutput.openTag(ELEMENT_NAME, attributeList);
161: getSourceLines().writeXML(xmlOutput, addMessages);
162: if (addMessages) {
163: xmlOutput.openTag(BugAnnotation.MESSAGE_TAG);
164: xmlOutput.writeText(this .toString());
165: xmlOutput.closeTag(BugAnnotation.MESSAGE_TAG);
166: }
167: xmlOutput.closeTag(ELEMENT_NAME);
168:
169: }
170: }
171:
172: // vim:ts=4
|