blob: d3deae898153723b354cc8be0dc240dfaab48b2f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2012 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0, which accompanies this distribution
* and is available at http://www.eclipse.org/legal/epl-v10.html.
*
* Contributors:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.common.core.internal.resource.java.binary;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Vector;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeParameter;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jpt.common.core.JptCommonCorePlugin;
import org.eclipse.jpt.common.core.resource.java.JavaResourceAttribute;
import org.eclipse.jpt.common.core.resource.java.JavaResourceType;
import org.eclipse.jpt.common.utility.internal.ClassName;
import org.eclipse.jpt.common.utility.internal.StringTools;
import org.eclipse.jpt.common.utility.internal.iterables.ListIterable;
import org.eclipse.jpt.common.utility.internal.iterables.LiveCloneIterable;
import org.eclipse.jpt.common.utility.internal.iterables.LiveCloneListIterable;
/**
* binary attribute (field or property)
*/
abstract class BinaryAttribute
extends BinaryMember
implements JavaResourceAttribute
{
private int modifiers;
private String typeName;
private boolean typeIsInterface;
private boolean typeIsEnum;
private boolean typeIsArray;
private int typeArrayDimensionality;
private String typeArrayComponentTypeName;
private final Vector<String> typeSuperclassNames = new Vector<String>();
private final Vector<String> typeInterfaceNames = new Vector<String>();
private final Vector<String> typeTypeArgumentNames = new Vector<String>();
protected BinaryAttribute(JavaResourceType parent, Adapter adapter) {
super(parent, adapter);
IMember member = adapter.getElement();
this.modifiers = this.buildModifiers(member);
String typeSignature = getTypeSignature();
Iterable<ITypeParameter> typeParameters = getAdapter().getTypeParameters();
this.typeName = buildTypeName(typeSignature, typeParameters);
this.typeIsArray = buildTypeIsArray(typeSignature);
this.typeArrayDimensionality = buildTypeArrayDimensionality(typeSignature);
this.typeArrayComponentTypeName = buildTypeArrayComponentTypeName(typeSignature, typeParameters);
this.typeTypeArgumentNames.addAll(buildTypeTypeArgumentNames(typeSignature, typeParameters));
IType type = this.getType(member.getJavaProject());
// if the type is an array, then the following will be false or empty
this.typeIsInterface = this.buildTypeIsInterface(type);
this.typeIsEnum = this.buildTypeIsEnum(type);
this.typeSuperclassNames.addAll(this.buildTypeSuperclassNames(type));
this.typeInterfaceNames.addAll(this.buildTypeInterfaceNames(type));
}
// ******** overrides ********
@Override
public void update() {
super.update();
String typeSignature = getTypeSignature();
Iterable<ITypeParameter> typeParameters = getAdapter().getTypeParameters();
setTypeName(buildTypeName(typeSignature, typeParameters));
setTypeIsArray(buildTypeIsArray(typeSignature));
setTypeArrayDimensionality(buildTypeArrayDimensionality(typeSignature));
setTypeArrayComponentTypeName(buildTypeArrayComponentTypeName(typeSignature, typeParameters));
setTypeTypeArgumentNames(buildTypeTypeArgumentNames(typeSignature, typeParameters));
}
@Override
protected void update(IMember member) {
super.update(member);
this.setModifiers(this.buildModifiers(member));
IType type = this.getType(member.getJavaProject()); // if the type is an array, then the following will be false or empty
this.setTypeIsInterface(this.buildTypeIsInterface(type));
this.setTypeIsEnum(this.buildTypeIsEnum(type));
this.setTypeSuperclassNames(this.buildTypeSuperclassNames(type));
this.setTypeInterfaceNames(this.buildTypeInterfaceNames(type));
}
@Override
public void toString(StringBuilder sb) {
sb.append(this.getName());
}
// ********** BinaryPersistentMember implementation **********
private Adapter getAdapter() {
return (Adapter) this.adapter;
}
// ********** JavaResourceAttribute implementation **********
@Override
public JavaResourceType getParent() {
return (JavaResourceType) super.getParent();
}
public JavaResourceType getResourceType() {
return this.getParent();
}
public String getName() {
return this.getAdapter().getAttributeName();
}
public boolean typeIsSubTypeOf(String tn) {
return ((this.typeName != null) && this.typeName.equals(tn))
|| this.typeInterfaceNames.contains(tn)
|| this.typeSuperclassNames.contains(tn);
}
public boolean typeIsVariablePrimitive() {
return (this.typeName != null) && ClassName.isVariablePrimitive(this.typeName);
}
// ***** modifiers
public int getModifiers() {
return this.modifiers;
}
private void setModifiers(int modifiers) {
int old = this.modifiers;
this.modifiers = modifiers;
this.firePropertyChanged(MODIFIERS_PROPERTY, old, modifiers);
}
/**
* zero seems like a reasonable default...
*/
private int buildModifiers(IMember member) {
try {
return member.getFlags();
} catch (JavaModelException ex) {
JptCommonCorePlugin.log(ex);
return 0;
}
}
// ***** type name
public String getTypeName() {
return this.typeName;
}
private void setTypeName(String typeName) {
String old = this.typeName;
this.typeName = typeName;
this.firePropertyChanged(TYPE_NAME_PROPERTY, old, typeName);
}
private String buildTypeName(String typeSignature, Iterable<ITypeParameter> typeParameters) {
return convertTypeSignatureToTypeName(typeSignature, typeParameters);
}
// ***** type is interface
public boolean typeIsInterface() {
return this.typeIsInterface;
}
private void setTypeIsInterface(boolean typeIsInterface) {
boolean old = this.typeIsInterface;
this.typeIsInterface = typeIsInterface;
this.firePropertyChanged(TYPE_IS_INTERFACE_PROPERTY, old, typeIsInterface);
}
private boolean buildTypeIsInterface(IType type) {
try {
return (type != null) && type.isInterface();
} catch (JavaModelException ex) {
JptCommonCorePlugin.log(ex);
return false;
}
}
// ***** type is enum
public boolean typeIsEnum() {
return this.typeIsEnum;
}
private void setTypeIsEnum(boolean typeIsEnum) {
boolean old = this.typeIsEnum;
this.typeIsEnum = typeIsEnum;
this.firePropertyChanged(TYPE_IS_ENUM_PROPERTY, old, typeIsEnum);
}
private boolean buildTypeIsEnum(IType type) {
try {
return (type != null) && type.isEnum();
} catch (JavaModelException ex) {
JptCommonCorePlugin.log(ex);
return false;
}
}
// ***** type is array
public boolean typeIsArray() {
return this.typeIsArray;
}
private void setTypeIsArray(boolean typeIsArray) {
boolean old = this.typeIsArray;
this.typeIsArray = typeIsArray;
this.firePropertyChanged(TYPE_IS_ARRAY_PROPERTY, old, typeIsArray);
}
private boolean buildTypeIsArray(String typeSignature) {
return convertTypeSignatureToTypeIsArray(typeSignature);
}
// ***** type array dimensionality
public int getTypeArrayDimensionality() {
return this.typeArrayDimensionality;
}
private void setTypeArrayDimensionality(int typeArrayDimensionality) {
int old = this.typeArrayDimensionality;
this.typeArrayDimensionality = typeArrayDimensionality;
firePropertyChanged(TYPE_ARRAY_DIMENSIONALITY_PROPERTY, old, typeArrayDimensionality);
}
private int buildTypeArrayDimensionality(String typeSignature) {
return convertTypeSignatureToTypeArrayDimensionality(typeSignature);
}
// ***** type array component type name
public String getTypeArrayComponentTypeName() {
return this.typeArrayComponentTypeName;
}
private void setTypeArrayComponentTypeName(String typeArrayComponentTypeName) {
String old = this.typeArrayComponentTypeName;
this.typeArrayComponentTypeName = typeArrayComponentTypeName;
firePropertyChanged(TYPE_ARRAY_COMPONENT_TYPE_NAME_PROPERTY, old, typeArrayComponentTypeName);
}
private String buildTypeArrayComponentTypeName(String typeSignature, Iterable<ITypeParameter> typeParameters) {
int arrayDimensionality = convertTypeSignatureToTypeArrayDimensionality(typeSignature);
return (arrayDimensionality == 0) ? null : convertTypeSignatureToTypeArrayComponentTypeName(typeSignature, typeParameters);
}
// ***** type superclass hierarchy
public ListIterable<String> getTypeSuperclassNames() {
return new LiveCloneListIterable<String>(this.typeSuperclassNames);
}
public boolean typeSuperclassNamesContains(String superclassName) {
return this.typeSuperclassNames.contains(superclassName);
}
private void setTypeSuperclassNames(List<String> typeSuperclassNames) {
this.synchronizeList(typeSuperclassNames, this.typeSuperclassNames, TYPE_SUPERCLASS_NAMES_LIST);
}
private List<String> buildTypeSuperclassNames(IType type) {
if (type == null) {
return Collections.emptyList();
}
ArrayList<String> names = new ArrayList<String>();
type = this.findSuperclass(type);
while (type != null) {
names.add(type.getFullyQualifiedName('.')); // no parameters are included here
type = this.findSuperclass(type);
}
return names;
}
// ***** type interface hierarchy
public Iterable<String> getTypeInterfaceNames() {
return new LiveCloneIterable<String>(this.typeInterfaceNames);
}
public boolean typeInterfaceNamesContains(String interfaceName) {
return this.typeInterfaceNames.contains(interfaceName);
}
private void setTypeInterfaceNames(Collection<String> typeInterfaceNames) {
this.synchronizeCollection(typeInterfaceNames, this.typeInterfaceNames, TYPE_INTERFACE_NAMES_COLLECTION);
}
private Collection<String> buildTypeInterfaceNames(IType type) {
if (type == null) {
return Collections.emptySet();
}
HashSet<String> names = new HashSet<String>();
while (type != null) {
this.addInterfaceNamesTo(type, names);
type = this.findSuperclass(type);
}
return names;
}
private void addInterfaceNamesTo(IType type, HashSet<String> names) {
for (String interfaceSignature : this.getSuperInterfaceTypeSignatures(type)) {
String interfaceName = convertTypeSignatureToTypeName(interfaceSignature);
names.add(interfaceName);
IType interfaceType = this.findType(interfaceName, type.getJavaProject());
if (interfaceType != null) {
this.addInterfaceNamesTo(interfaceType, names); // recurse
}
}
}
// ***** type type argument names
public ListIterable<String> getTypeTypeArgumentNames() {
return new LiveCloneListIterable<String>(this.typeTypeArgumentNames);
}
public int getTypeTypeArgumentNamesSize() {
return this.typeTypeArgumentNames.size();
}
public String getTypeTypeArgumentName(int index) {
return this.typeTypeArgumentNames.get(index);
}
private void setTypeTypeArgumentNames(List<String> typeTypeArgumentNames) {
this.synchronizeList(typeTypeArgumentNames, this.typeTypeArgumentNames, TYPE_TYPE_ARGUMENT_NAMES_LIST);
}
private List<String> buildTypeTypeArgumentNames(String typeSignature, Iterable<ITypeParameter> typeParameters) {
int arrayDimensionality = convertTypeSignatureToTypeArrayDimensionality(typeSignature);
return (arrayDimensionality != 0) ? Collections.<String>emptyList() : convertTypeSignatureToTypeTypeArgumentNames(typeSignature, typeParameters);
}
// ********** convenience methods **********
private String getTypeSignature() {
try {
return this.getAdapter().getTypeSignature();
} catch (JavaModelException ex) {
JptCommonCorePlugin.log(ex);
return null;
}
}
private IType findSuperclass(IType type) {
return this.findTypeBySignature(this.getSuperclassSignature(type), type.getJavaProject());
}
private String getSuperclassSignature(IType type) {
try {
return type.getSuperclassTypeSignature();
} catch (JavaModelException ex) {
JptCommonCorePlugin.log(ex);
return null;
}
}
private String[] getSuperInterfaceTypeSignatures(IType type) {
try {
return type.getSuperInterfaceTypeSignatures();
} catch (JavaModelException ex) {
JptCommonCorePlugin.log(ex);
return StringTools.EMPTY_STRING_ARRAY;
}
}
private IType findTypeBySignature(String typeSignature, IJavaProject javaProject) {
return (typeSignature == null) ? null : findType(convertTypeSignatureToTypeName_(typeSignature), javaProject);
}
private IType getType(IJavaProject javaProject) {
return (this.typeName == null) ? null : findType(this.typeName, javaProject);
}
private static IType findType(String fullyQualifiedName, IJavaProject javaProject) {
try {
return javaProject.findType(fullyQualifiedName);
} catch (JavaModelException ex) {
JptCommonCorePlugin.log(ex);
return null;
}
}
// ********** adapters **********
/**
* Adapt an IField or IMethod.
*/
interface Adapter
extends BinaryMember.Adapter {
/**
* Return the field or getter method's "attribute" name
* (e.g. field "foo" -> "foo"; method "getFoo" -> "foo").
*/
String getAttributeName();
/**
* Return the attribute's type signature.
*/
String getTypeSignature() throws JavaModelException;
}
}