001    package edu.rice.cs.cunit.instrumentors.threadCheck;
002    
003    import edu.rice.cs.cunit.instrumentors.util.IScannerStrategy;
004    
005    /**
006         * Storage class for subtyping warnings.
007     */
008    public class SubtypingWarning implements IScannerStrategy.IScanResult, Comparable<SubtypingWarning> {
009        /**
010         * Name of the subclass that contained the annotation.
011         */
012        public final String subClassName;
013    
014        /**
015         * Name of the superclass that did not contain the annotation.
016         */
017        public final String superClassName;
018    
019        /**
020         * Name of the method.
021         */
022        public final String methodName;
023    
024        /**
025         * Descriptor of the method.
026         */
027        public final String methodDescriptor;
028    
029        /**
030         * Name of the annotation.
031         */
032        public final String annotationName;
033    
034        /**
035         * Create a new subtyping warning
036         * @param subClassName name of the subclass that contained the annotation
037         * @param superClassName name of the superclass that did not contain the annotation
038         * @param methodName name of the method, or null if on class level
039         * @param methodDescriptor descriptor of the method, or null if on class level
040         * @param annotationName name of the annotation
041         */
042        public SubtypingWarning(String subClassName,
043                                String superClassName,
044                                String methodName,
045                                String methodDescriptor,
046                                String annotationName) {
047            this.subClassName = subClassName;
048            this.superClassName = superClassName;
049            this.methodName = methodName;
050            this.methodDescriptor = methodDescriptor;
051            this.annotationName = annotationName;
052        }
053    
054        /**
055         * Return true if this object is equal to the other object.
056         * @param o other object
057         * @return true if equal
058         */
059        public boolean equals(Object o) {
060            if (this == o) {
061                return true;
062            }
063            if (o == null || getClass() != o.getClass()) {
064                return false;
065            }
066    
067            SubtypingWarning that = (SubtypingWarning)o;
068    
069            if (annotationName != null ? !annotationName.equals(that.annotationName) : that.annotationName != null) {
070                return false;
071            }
072            if (methodDescriptor != null ? !methodDescriptor.equals(that.methodDescriptor) :
073                that.methodDescriptor != null) {
074                return false;
075            }
076            if (methodName != null ? !methodName.equals(that.methodName) : that.methodName != null) {
077                return false;
078            }
079            if (subClassName != null ? !subClassName.equals(that.subClassName) : that.subClassName != null) {
080                return false;
081            }
082            if (superClassName != null ? !superClassName.equals(that.superClassName) : that.superClassName != null) {
083                return false;
084            }
085    
086            return true;
087        }
088    
089        /**
090         * Return a hash code for this object.
091         * @return hash code
092         */
093        public int hashCode() {
094            int result;
095            result = (subClassName != null ? subClassName.hashCode() : 0);
096            result = 31 * result + (superClassName != null ? superClassName.hashCode() : 0);
097            result = 31 * result + (methodName != null ? methodName.hashCode() : 0);
098            result = 31 * result + (methodDescriptor != null ? methodDescriptor.hashCode() : 0);
099            result = 31 * result + (annotationName != null ? annotationName.hashCode() : 0);
100            return result;
101        }
102    
103        /**
104         * Compares this object with the specified object for order.
105         * @param o the Object to be compared.
106         *
107         * @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than
108         *         the specified object.
109         *
110         * @throws ClassCastException if the specified object's type prevents it from being compared to this Object.
111         */
112        public int compareTo(SubtypingWarning o) {
113            int res;
114            res = subClassName.compareTo(o.subClassName);
115            if(res!=0) { return res; }
116    
117            if ((methodName==null) || (methodDescriptor==null)) {
118                if ((o.methodName!=null) && (methodDescriptor!=null)) {
119                    return -1; // put class warnings before method warnings
120                }
121            }
122            if ((methodName!=null) && (methodDescriptor!=null)) {
123                if ((o.methodName==null)) {
124                    return 1; // put class warnings before method warnings
125                }
126            }
127    
128            if ((methodName!=null) && (methodDescriptor==null)) {
129                res = methodName.compareTo(o.methodName);
130                if(res!=0) { return res; }
131                res = methodDescriptor.compareTo(o.methodDescriptor);
132                if(res!=0) { return res; }
133            }
134    
135            res = annotationName.compareTo(o.annotationName);
136            if(res!=0) { return res; }
137    
138            res = superClassName.compareTo(o.superClassName);
139            if(res!=0) { return res; }
140    
141            return 0;
142        }
143    
144        /**
145         * Returns a string representation of the object.
146         * @return a string representation of the object
147         */
148        public String toString() {
149            StringBuilder sb = new StringBuilder();
150            if ((methodName==null) || (methodDescriptor==null)) {
151                // class level warning
152                sb.append(subClassName);
153                sb.append(" has ");
154                sb.append(annotationName);
155                sb.append(" but ");
156                sb.append(superClassName);
157                sb.append(" does not");
158            }
159            else {
160                // method level warning
161                sb.append(subClassName);
162                sb.append('.');
163                sb.append(methodName);
164                sb.append(methodDescriptor);
165                sb.append(" has ");
166                sb.append(annotationName);
167                sb.append(" but ");
168                sb.append(superClassName);
169                sb.append('.');
170                sb.append(methodName);
171                sb.append(methodDescriptor);
172                sb.append(" does not");
173            }
174            return sb.toString();
175        }
176    
177        /**
178         * Return the name of the property that was scanned for.
179         * @return property name
180         */
181        public String getPropertyName() {
182            return "ThreadChecker Subtyping Warnings";
183        }
184    }