/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.symboltable;
import java.util.HashSet;
import java.util.Set;
/**
* Just stores a type image and a actual type. And makes it easy to compare
* these.
*/
public class SimpleTypedNameDeclaration implements TypedNameDeclaration {
private final String typeImage;
private final Class<?> type;
private SimpleTypedNameDeclaration next;
private static Set<String> primitiveTypes = new HashSet<>();
static {
primitiveTypes.add("float");
primitiveTypes.add("double");
primitiveTypes.add("int");
primitiveTypes.add("integer");
primitiveTypes.add("long");
primitiveTypes.add("byte");
primitiveTypes.add("short");
primitiveTypes.add("boolean");
primitiveTypes.add("char");
primitiveTypes.add("character");
}
/**
* Creates a new {@link SimpleTypedNameDeclaration} with the given type
*
* @param typeImage
* the type image
* @param type
* the actual type
*/
public SimpleTypedNameDeclaration(String typeImage, Class<?> type) {
this.typeImage = typeImage;
this.type = type;
}
public SimpleTypedNameDeclaration(String typeImage, Class<?> type, SimpleTypedNameDeclaration next) {
this.typeImage = typeImage;
this.type = type;
this.next = next;
}
public void addNext(SimpleTypedNameDeclaration next) {
if (next == null) {
return;
}
if (this.next == null) {
this.next = next;
} else {
this.next.addNext(next);
}
}
@Override
public String getTypeImage() {
return typeImage;
}
@Override
public Class<?> getType() {
return type;
}
@Override
public String toString() {
String nextString = next != null ? "(next: " + next + ")" : "";
return "SimpleType:" + type + "/" + typeImage + nextString;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((type == null) ? 0 : type.hashCode());
result = prime * result + ((typeImage == null) ? 0 : typeImage.hashCode());
return result;
}
/**
* {@inheritDoc}
* <p>
* Additionally - two {@link SimpleTypedNameDeclaration} are equal, if they
* contain types, that can be cast into each other.
* </p>
*/
@Override
public boolean equals(Object obj) {
return internalEquals(obj) || internalEqualsNext(obj);
}
private boolean internalEqualsNext(Object obj) {
if (next != null) {
return next.equals(obj);
}
if (obj instanceof SimpleTypedNameDeclaration) {
SimpleTypedNameDeclaration otherNext = ((SimpleTypedNameDeclaration) obj).next;
if (otherNext != null) {
return otherNext.equals(this);
}
}
return false;
}
private boolean internalEquals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
SimpleTypedNameDeclaration other = (SimpleTypedNameDeclaration) obj;
if (type == null) {
if (other.type == Object.class) {
return true;
}
if (other.type != null) {
return false;
}
}
if (type != null && (type.equals(other.type) || type == Object.class)) {
return true;
}
// if the type is given, only compare the type and don't care about the
// type image
if (type != null && other.type != null
&& (type.isAssignableFrom(other.type) || other.type.isAssignableFrom(type))) {
return true;
}
if (typeImage == null) {
if (other.typeImage != null) {
return false;
}
} else if (!typeImage.equals(other.typeImage)) {
// consider auto-boxing
if (other.typeImage != null) {
String lcType = typeImage.toLowerCase();
String otherLcType = other.typeImage.toLowerCase();
if (primitiveTypes.contains(lcType) && primitiveTypes.contains(otherLcType)) {
if (lcType.equals(otherLcType)) {
return true;
} else if (("char".equals(lcType) || "character".equals(lcType))
&& ("char".equals(otherLcType) || "character".equals(otherLcType))) {
return true;
} else if (("int".equals(lcType) || "integer".equals(lcType))
&& ("int".equals(otherLcType) || "integer".equals(otherLcType)
|| "short".equals(otherLcType) || "char".equals(otherLcType)
|| "character".equals(otherLcType) || "byte".equals(otherLcType))) {
return true;
} else if ("double".equals(lcType) && ("float".equals(otherLcType) || "int".equals(otherLcType)
|| "integer".equals(otherLcType) || "long".equals(otherLcType))) {
return true;
} else if ("float".equals(lcType) && ("int".equals(otherLcType) || "integer".equals(otherLcType)
|| "long".equals(otherLcType))) {
return true;
} else if ("long".equals(lcType) && ("int".equals(otherLcType) || "integer".equals(otherLcType)
|| "char".equals(otherLcType) || "character".equals(otherLcType))) {
return true;
}
}
}
return false;
}
return true;
}
}