View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.symboltable;
5   
6   import java.util.HashSet;
7   import java.util.Set;
8   
9   /**
10   * Just stores a type image and a actual type. And makes it easy to compare
11   * these.
12   */
13  public class SimpleTypedNameDeclaration implements TypedNameDeclaration {
14  
15      final private String typeImage;
16      final private Class<?> type;
17      private SimpleTypedNameDeclaration next;
18  
19      /**
20       * Creates a new {@link SimpleTypedNameDeclaration} with the given type
21       * 
22       * @param typeImage
23       *            the type image
24       * @param type
25       *            the actual type
26       */
27      public SimpleTypedNameDeclaration(String typeImage, Class<?> type) {
28          this.typeImage = typeImage;
29          this.type = type;
30      }
31  
32      public SimpleTypedNameDeclaration(String typeImage, Class<?> type, SimpleTypedNameDeclaration next) {
33          this.typeImage = typeImage;
34          this.type = type;
35          this.next = next;
36      }
37  
38      public void addNext(SimpleTypedNameDeclaration next) {
39          if (next == null) {
40              return;
41          }
42  
43          if (this.next == null) {
44              this.next = next;
45          } else {
46              this.next.addNext(next);
47          }
48      }
49  
50      @Override
51      public String getTypeImage() {
52          return typeImage;
53      }
54  
55      @Override
56      public Class<?> getType() {
57          return type;
58      }
59  
60      @Override
61      public String toString() {
62          String nextString = next != null ? "(next: " + next + ")" : "";
63          return "SimpleType:" + type + "/" + typeImage + nextString;
64      }
65  
66      @Override
67      public int hashCode() {
68          final int prime = 31;
69          int result = 1;
70          result = prime * result + ((type == null) ? 0 : type.hashCode());
71          result = prime * result + ((typeImage == null) ? 0 : typeImage.hashCode());
72          return result;
73      }
74  
75      /**
76       * {@inheritDoc}
77       * <p>
78       * Additionally - two {@link SimpleTypedNameDeclaration} are equal, if they
79       * contain types, that can be cast into each other.
80       * </p>
81       */
82      @Override
83      public boolean equals(Object obj) {
84          return internalEquals(obj) || internalEqualsNext(obj);
85      }
86  
87      private boolean internalEqualsNext(Object obj) {
88          if (next != null) {
89              return next.equals(obj);
90          }
91          if (obj instanceof SimpleTypedNameDeclaration) {
92              SimpleTypedNameDeclaration otherNext = ((SimpleTypedNameDeclaration) obj).next;
93              if (otherNext != null) {
94                  return otherNext.equals(this);
95              }
96          }
97          return false;
98      }
99  
100     private boolean internalEquals(Object obj) {
101         if (this == obj) {
102             return true;
103         }
104         if (obj == null) {
105             return false;
106         }
107         if (getClass() != obj.getClass()) {
108             return false;
109         }
110         SimpleTypedNameDeclaration other = (SimpleTypedNameDeclaration) obj;
111         if (type == null) {
112             if (other.type == Object.class) {
113                 return true;
114             }
115             if (other.type != null) {
116                 return false;
117             }
118         }
119         if (type != null && (type.equals(other.type) || type == Object.class)) {
120             return true;
121         }
122 
123         // if the type is given, only compare the type and don't care about the
124         // type image
125         if (type != null && other.type != null
126                 && (type.isAssignableFrom(other.type) || other.type.isAssignableFrom(type))) {
127             return true;
128         }
129 
130         if (typeImage == null) {
131             if (other.typeImage != null) {
132                 return false;
133             }
134         } else if (!typeImage.equals(other.typeImage)) {
135             // consider auto-boxing
136             if (other.typeImage != null) {
137                 String lcType = typeImage.toLowerCase();
138                 String otherLcType = other.typeImage.toLowerCase();
139                 if (primitiveTypes.contains(lcType) && primitiveTypes.contains(otherLcType)) {
140                     if (lcType.equals(otherLcType)) {
141                         return true;
142                     } else if ((lcType.equals("char") || lcType.equals("character"))
143                             && (otherLcType.equals("char") || otherLcType.equals("character"))) {
144                         return true;
145                     } else if ((lcType.equals("int") || lcType.equals("integer"))
146                             && (otherLcType.equals("int") || otherLcType.equals("integer")
147                                     || otherLcType.equals("short") || otherLcType.equals("char")
148                                     || otherLcType.equals("character") || otherLcType.equals("byte"))) {
149                         return true;
150                     } else if (lcType.equals("double")
151                             && (otherLcType.equals("float") || otherLcType.equals("int")
152                                     || otherLcType.equals("integer") || otherLcType.equals("long"))) {
153                         return true;
154                     } else if (lcType.equals("float")
155                             && (otherLcType.equals("int") || otherLcType.equals("integer") || otherLcType
156                                     .equals("long"))) {
157                         return true;
158                     } else if (lcType.equals("long")
159                             && (otherLcType.equals("int") || otherLcType.equals("integer")
160                                     || otherLcType.equals("char") || otherLcType.equals("character"))) {
161                         return true;
162                     }
163                 }
164             }
165             return false;
166         }
167         return true;
168     }
169 
170     private static Set<String> primitiveTypes = new HashSet<>();
171     static {
172         primitiveTypes.add("float");
173         primitiveTypes.add("double");
174         primitiveTypes.add("int");
175         primitiveTypes.add("integer");
176         primitiveTypes.add("long");
177         primitiveTypes.add("byte");
178         primitiveTypes.add("short");
179         primitiveTypes.add("boolean");
180         primitiveTypes.add("char");
181         primitiveTypes.add("character");
182     }
183 }