/** | |
* Copyright (c) 2009 Mia-Software. | |
* 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: | |
* Romain DERVAUX (Mia-Software) - initial API and implementation | |
*******************************************************************************/ | |
package org.eclipse.modisco.java.discoverer.internal.io.library; | |
import org.eclipse.gmt.modisco.java.ASTNode; | |
import org.eclipse.gmt.modisco.java.AbstractMethodDeclaration; | |
import org.eclipse.gmt.modisco.java.AbstractTypeDeclaration; | |
import org.eclipse.gmt.modisco.java.Annotation; | |
import org.eclipse.gmt.modisco.java.AnnotationMemberValuePair; | |
import org.eclipse.gmt.modisco.java.AnnotationTypeMemberDeclaration; | |
import org.eclipse.gmt.modisco.java.Archive; | |
import org.eclipse.gmt.modisco.java.ArrayInitializer; | |
import org.eclipse.gmt.modisco.java.ArrayType; | |
import org.eclipse.gmt.modisco.java.BodyDeclaration; | |
import org.eclipse.gmt.modisco.java.BooleanLiteral; | |
import org.eclipse.gmt.modisco.java.CharacterLiteral; | |
import org.eclipse.gmt.modisco.java.ClassDeclaration; | |
import org.eclipse.gmt.modisco.java.ClassFile; | |
import org.eclipse.gmt.modisco.java.EnumConstantDeclaration; | |
import org.eclipse.gmt.modisco.java.EnumDeclaration; | |
import org.eclipse.gmt.modisco.java.Expression; | |
import org.eclipse.gmt.modisco.java.FieldDeclaration; | |
import org.eclipse.gmt.modisco.java.InheritanceKind; | |
import org.eclipse.gmt.modisco.java.MethodDeclaration; | |
import org.eclipse.gmt.modisco.java.Model; | |
import org.eclipse.gmt.modisco.java.Modifier; | |
import org.eclipse.gmt.modisco.java.NumberLiteral; | |
import org.eclipse.gmt.modisco.java.Package; | |
import org.eclipse.gmt.modisco.java.ParameterizedType; | |
import org.eclipse.gmt.modisco.java.PrimitiveType; | |
import org.eclipse.gmt.modisco.java.SingleVariableAccess; | |
import org.eclipse.gmt.modisco.java.SingleVariableDeclaration; | |
import org.eclipse.gmt.modisco.java.StringLiteral; | |
import org.eclipse.gmt.modisco.java.TypeAccess; | |
import org.eclipse.gmt.modisco.java.TypeDeclaration; | |
import org.eclipse.gmt.modisco.java.TypeLiteral; | |
import org.eclipse.gmt.modisco.java.TypeParameter; | |
import org.eclipse.gmt.modisco.java.UnresolvedItem; | |
import org.eclipse.gmt.modisco.java.UnresolvedItemAccess; | |
import org.eclipse.gmt.modisco.java.VariableDeclarationFragment; | |
import org.eclipse.gmt.modisco.java.VisibilityKind; | |
import org.eclipse.gmt.modisco.java.WildCardType; | |
import org.eclipse.gmt.modisco.java.emf.JavaFactory; | |
import org.eclipse.jdt.core.Flags; | |
import org.eclipse.jdt.core.IAnnotation; | |
import org.eclipse.jdt.core.IClassFile; | |
import org.eclipse.jdt.core.IField; | |
import org.eclipse.jdt.core.IJavaElement; | |
import org.eclipse.jdt.core.IMember; | |
import org.eclipse.jdt.core.IMemberValuePair; | |
import org.eclipse.jdt.core.IMethod; | |
import org.eclipse.jdt.core.IPackageFragment; | |
import org.eclipse.jdt.core.IType; | |
import org.eclipse.jdt.core.ITypeParameter; | |
import org.eclipse.jdt.core.JavaModelException; | |
import org.eclipse.jdt.core.Signature; | |
import org.eclipse.modisco.java.discoverer.internal.io.java.JDTVisitor; | |
import org.eclipse.modisco.java.discoverer.internal.io.java.JDTVisitorUtils; | |
import org.eclipse.modisco.java.discoverer.internal.io.java.binding.Binding; | |
import org.eclipse.modisco.java.discoverer.internal.io.java.binding.BindingManager; | |
import org.eclipse.modisco.java.discoverer.internal.io.java.binding.ClassBinding; | |
import org.eclipse.modisco.java.discoverer.internal.io.java.binding.FieldBinding; | |
import org.eclipse.modisco.java.discoverer.internal.io.java.binding.MethodBinding; | |
import org.eclipse.modisco.java.discoverer.internal.io.java.binding.PendingElement; | |
import org.eclipse.modisco.java.discoverer.internal.io.library.binding.JavaModelDelegateBindingFactory; | |
/** | |
* The main class for populating the Java model from the JDT Java model of | |
* {@link IClassFile class files}. | |
* | |
* @see Model | |
*/ | |
public class ClassFileParser { | |
/** | |
* the EMF factory | |
*/ | |
private JavaFactory factory; | |
/** | |
* the model | |
*/ | |
private final Model model; | |
/** | |
* the global {@code BindingManager} | |
*/ | |
private BindingManager globalBindings; | |
/** | |
* a {@code TypeFinder} | |
*/ | |
private final TypeFinder typeFinder; | |
/** | |
* the path of the currently visited class file | |
*/ | |
private final String filePath; | |
/** | |
* the {@code ClassFile} object associated with the .class file of the | |
* top-level type | |
*/ | |
private ClassFile cuNode; | |
/** | |
* the current package | |
*/ | |
private Package currentPackage; | |
/** | |
* the currently visited java type or method. Useful to retrieve type | |
* variable definition. | |
*/ | |
private IMember currentlyVisitedJavaElement = null; | |
public ClassFileParser(final JavaFactory factory, final Model resultModel, | |
final BindingManager globalBindings, final TypeFinder typeFinder, final String filePath) { | |
setFactory(factory); | |
this.model = resultModel; | |
setGlobalBindings(globalBindings); | |
this.typeFinder = typeFinder; | |
this.filePath = filePath; | |
} | |
/** | |
* Finds the type variable associated with the currently visited Java | |
* element (type or method) or with it's parent. | |
* | |
* @param name | |
* the name of the type variable | |
* @return the {@code ITypeParameter} | |
*/ | |
public ITypeParameter findTypeParameter(final String name) { | |
IMember member = this.currentlyVisitedJavaElement; | |
ITypeParameter typeParameter = null; | |
while (member != null) { | |
if (member.getElementType() == IJavaElement.METHOD) { | |
typeParameter = ((IMethod) member).getTypeParameter(name); | |
} else { | |
typeParameter = ((IType) member).getTypeParameter(name); | |
} | |
if (typeParameter.exists()) { | |
break; | |
} | |
member = member.getDeclaringType(); | |
} | |
return typeParameter; | |
} | |
public TypeFinder getTypeFinder() { | |
return this.typeFinder; | |
} | |
/** | |
* @see org.eclipse.modisco.java.discoverer.internal.io.java.JDTVisitor#initializeNode(ASTNode, | |
* org.eclipse.jdt.core.dom.ASTNode) | |
*/ | |
public void initializeNode(final ASTNode element) { | |
element.setOriginalClassFile(this.cuNode); | |
} | |
public void parse(final IClassFile classFile) throws JavaModelException { | |
IType type = classFile.getType(); | |
// we only want top level types | |
if (!type.exists() || type.isAnonymous() || type.isLocal() || type.isMember()) { | |
return; | |
} | |
// we check if this type has already been visited | |
Binding id = JavaModelDelegateBindingFactory.getInstance().getBindingForElement(type, this); | |
if (getGlobalBindings().containsTarget(id)) { | |
return; | |
} | |
visitPackage(type.getPackageFragment()); | |
visitClassFile(classFile); | |
Archive archive = LibraryReader.getArchive(classFile, getFactory(), this.model); | |
if (archive != null) { | |
// jar or zip file | |
archive.getClassFiles().add(this.cuNode); | |
} else { | |
// folder | |
this.model.getClassFiles().add(this.cuNode); | |
} | |
parse2(type, null); | |
} | |
/** | |
* Creation of the {@link ClassFile} object | |
* | |
* @param classFile | |
*/ | |
protected void visitClassFile(final IClassFile classFile) { | |
ClassFile element = getFactory().createClassFile(); | |
this.model.getClassFiles().add(element); | |
element.setName(classFile.getElementName()); | |
element.setOriginalFilePath(this.filePath); | |
element.setPackage(this.currentPackage); | |
this.cuNode = element; | |
} | |
/** | |
* Visit the members (fields, methods and types) of the {@code type}. | |
* | |
* @param type | |
* the java model {@code IType} | |
* @param enclosingType | |
* the MoDisco enclosing type of the {@code IType} | |
* @return the {@link AbstractTypeDeclaration} object corresponding to the | |
* {@code IType}, {@code null} if type does not exist. | |
* @throws JavaModelException | |
*/ | |
protected AbstractTypeDeclaration parse2(final IType type, | |
final AbstractTypeDeclaration enclosingType) throws JavaModelException { | |
AbstractTypeDeclaration typeDeclaration = visitType(type); | |
if (enclosingType == null) { | |
// the class file object registers the top level type | |
this.cuNode.setType(typeDeclaration); | |
} else { | |
// type is an member type | |
enclosingType.getBodyDeclarations().add(typeDeclaration); | |
} | |
// fields | |
for (IField f : type.getFields()) { | |
if (type.isEnum() && f.isEnumConstant()) { | |
EnumConstantDeclaration constant = visitEnumConstantDeclaration(f); | |
if (constant != null) { | |
((EnumDeclaration) typeDeclaration).getEnumConstants().add(constant); | |
} | |
} else { | |
// declaring type is an annotation, interface or type | |
FieldDeclaration field = visitField(f); | |
if (field != null) { | |
typeDeclaration.getBodyDeclarations().add(field); | |
} | |
} | |
} | |
// methods | |
for (IMethod m : type.getMethods()) { | |
BodyDeclaration method = null; | |
if (type.isAnnotation()) { | |
method = visitAnnotationTypeMemberDeclaration(m); | |
} else { | |
method = visitMethod(m); | |
} | |
if (method != null) { | |
typeDeclaration.getBodyDeclarations().add(method); | |
} | |
} | |
// member types | |
for (IType subType : type.getTypes()) { | |
if (subType.exists()) { | |
parse2(subType, typeDeclaration); | |
} | |
} | |
return typeDeclaration; | |
} | |
/** | |
* Visit the package of the class file. | |
* | |
* @param packageFragment | |
* the {@code IPackageFragment} | |
*/ | |
protected void visitPackage(final IPackageFragment packageFragment) { | |
Package element = null; | |
// the empty package | |
if (!packageFragment.exists() || packageFragment.getElementName().length() == 0) { | |
element = (Package) getGlobalBindings().getTarget(JDTVisitor.DEFAULT_PKG_ID); | |
if (element == null) { | |
element = getFactory().createPackage(); | |
element.setName(JDTVisitor.DEFAULT_PKG_ID); | |
element.setModel(this.model); | |
getGlobalBindings().addTarget(JDTVisitor.DEFAULT_PKG_ID, element); | |
} | |
} else { | |
// named package | |
Binding id = JavaModelDelegateBindingFactory.getInstance().getBindingForElement( | |
packageFragment, this); | |
if (!getGlobalBindings().containsTarget(id.toString())) { | |
element = createPackageHierarchy(packageFragment); | |
ClassFileParserUtils.manageBindingDeclaration(element, packageFragment, this); | |
} else { | |
element = (Package) getGlobalBindings().getTarget(id.toString()); | |
} | |
} | |
this.currentPackage = element; | |
} | |
// create iterately a hierarchy of packages | |
protected Package createPackageHierarchy(final IPackageFragment packageFragment) { | |
Package result = getFactory().createPackage(); | |
Binding id = JavaModelDelegateBindingFactory.getInstance().getBindingForElement( | |
packageFragment, this); | |
String currentPackageName = id.getName(); | |
Package localCurrentPackage = result; | |
int lastDotIndex = currentPackageName.lastIndexOf('.'); | |
if (lastDotIndex == -1) { | |
this.model.getOwnedElements().add(result); | |
localCurrentPackage.setName(currentPackageName); | |
} else { | |
// iterate on parents packages to create them if needed | |
localCurrentPackage.setName(currentPackageName.substring(lastDotIndex + 1)); | |
while (lastDotIndex > 0) { | |
// add qualified name for curent Package | |
currentPackageName = currentPackageName.substring(0, lastDotIndex); | |
Package aParentPackage = null; | |
if (!getGlobalBindings().containsTarget(currentPackageName)) { | |
aParentPackage = getFactory().createPackage(); | |
getGlobalBindings().addTarget(currentPackageName, aParentPackage); | |
lastDotIndex = currentPackageName.lastIndexOf('.'); | |
if (lastDotIndex < 0) { // top level package | |
this.model.getOwnedElements().add(aParentPackage); | |
aParentPackage.setName(currentPackageName); | |
} else { | |
aParentPackage.setName(currentPackageName.substring(lastDotIndex + 1)); | |
} | |
aParentPackage.getOwnedPackages().add(localCurrentPackage); | |
} else { | |
aParentPackage = (Package) getGlobalBindings().getTarget(currentPackageName); // (PackageDeclaration)binding.get(node); | |
aParentPackage.getOwnedPackages().add(localCurrentPackage); | |
break; // if this package is registered, parents packages | |
// also are | |
} | |
localCurrentPackage = aParentPackage; | |
} | |
} | |
return result; | |
} | |
/** | |
* Visit the properties of an {@code IType}. | |
* | |
* @param type | |
* the {@code IType} | |
* @return the {@link AbstractTypeDeclaration} object corresponding to the | |
* {@code IType} | |
* @throws JavaModelException | |
*/ | |
protected AbstractTypeDeclaration visitType(final IType type) throws JavaModelException { | |
AbstractTypeDeclaration element = null; | |
if (type.isEnum()) { | |
element = getFactory().createEnumDeclaration(); | |
} else if (type.isAnnotation()) { | |
element = getFactory().createAnnotationTypeDeclaration(); | |
} else if (type.isInterface()) { | |
element = getFactory().createInterfaceDeclaration(); | |
} else { | |
element = getFactory().createClassDeclaration(); | |
} | |
this.currentlyVisitedJavaElement = type; | |
initializeNode(element); | |
element.setName(type.getElementName()); | |
element.setPackage(this.currentPackage); | |
this.currentPackage.getOwnedElements().add(element); | |
// superClass | |
// enums are classes but can't have explicit superclass | |
String superClass = type.getSuperclassTypeSignature(); | |
if (type.isClass() && superClass != null | |
&& !ClassFileParserUtils.isJavaLangObject(superClass)) { | |
((ClassDeclaration) element).setSuperClass(getRefOnType(superClass)); | |
} | |
// superInterfaces | |
// annotations can't have explicit annotations | |
if (!type.isAnnotation()) { | |
for (String superInterface : type.getSuperInterfaceTypeSignatures()) { | |
if (!ClassFileParserUtils.isJavaLangObject(superInterface)) { | |
element.getSuperInterfaces().add(getRefOnType(superInterface)); | |
} | |
} | |
} | |
// type parameters | |
ITypeParameter[] parameters = type.getTypeParameters(); | |
for (ITypeParameter parameter : parameters) { | |
TypeParameter t = getFactory().createTypeParameter(); | |
((TypeDeclaration) element).getTypeParameters().add(t); | |
visitTypeParameter(parameter, t); | |
} | |
// annotations | |
for (IAnnotation annotation : type.getAnnotations()) { | |
Annotation anno = getFactory().createAnnotation(); | |
element.getAnnotations().add(anno); | |
visitAnnotation(annotation, anno); | |
} | |
// visibility modifier | |
Modifier m = getFactory().createModifier(); | |
element.setModifier(m); | |
m.setBodyDeclaration(element); | |
manageModifier(m, type.getFlags(), type); | |
ClassFileParserUtils.manageBindingDeclaration(element, type, this); | |
return element; | |
} | |
/** | |
* Visit a {@code IField}. | |
* | |
* @param field | |
* the {@code IField} | |
* @return the {@link FieldDeclaration} object corresponding to the | |
* {@code IField}, or {@code null} if the field does not exist or is | |
* {@link org.eclipse.jdt.core.Flags#isSynthetic(int) synthetic} | |
* @throws JavaModelException | |
*/ | |
protected FieldDeclaration visitField(final IField field) throws JavaModelException { | |
if (Flags.isSynthetic(field.getFlags())) { | |
return null; | |
} | |
FieldDeclaration element = getFactory().createFieldDeclaration(); | |
initializeNode(element); | |
// type | |
String type = field.getTypeSignature(); | |
element.setType(getRefOnType(type)); | |
// visibility modifier | |
Modifier m = getFactory().createModifier(); | |
element.setModifier(m); | |
m.setBodyDeclaration(element); | |
manageModifier(m, field.getFlags(), field); | |
// the fragment of this field | |
VariableDeclarationFragment fragment = getFactory().createVariableDeclarationFragment(); | |
initializeNode(fragment); | |
fragment.setExtraArrayDimensions(0); | |
fragment.setName(field.getElementName()); | |
fragment.setVariablesContainer(element); | |
for (IAnnotation annotation : field.getAnnotations()) { | |
Annotation anno = getFactory().createAnnotation(); | |
element.getAnnotations().add(anno); | |
visitAnnotation(annotation, anno); | |
} | |
ClassFileParserUtils.manageBindingDeclaration(fragment, field, this); | |
return element; | |
} | |
protected AnnotationTypeMemberDeclaration visitAnnotationTypeMemberDeclaration( | |
final IMethod method) throws JavaModelException { | |
AnnotationTypeMemberDeclaration element = getFactory() | |
.createAnnotationTypeMemberDeclaration(); | |
initializeNode(element); | |
element.setName(method.getElementName()); | |
element.setType(getRefOnType(method.getReturnType())); | |
// the default value of this annotation member | |
IMemberValuePair defaultValue = method.getDefaultValue(); | |
if (defaultValue != null) { | |
Expression result = manageMemberValuePair(defaultValue); | |
element.setDefault(result); | |
} | |
Modifier m = getFactory().createModifier(); | |
m.setBodyDeclaration(element); | |
element.setModifier(m); | |
manageModifier(m, method.getFlags(), method); | |
ClassFileParserUtils.manageBindingDeclaration(element, method, this); | |
return element; | |
} | |
protected EnumConstantDeclaration visitEnumConstantDeclaration(final IField field) | |
throws JavaModelException { | |
EnumConstantDeclaration element = getFactory().createEnumConstantDeclaration(); | |
initializeNode(element); | |
element.setName(field.getElementName()); | |
element.setModifier(getFactory().createModifier()); | |
// annotations | |
for (IAnnotation annotation : field.getAnnotations()) { | |
Annotation anno = getFactory().createAnnotation(); | |
element.getAnnotations().add(anno); | |
visitAnnotation(annotation, anno); | |
} | |
ClassFileParserUtils.manageBindingDeclaration(element, field, this); | |
return element; | |
} | |
/** | |
* Visit a {@code IMethod}. | |
* | |
* @param method | |
* the {@code IMethod} | |
* @return the {@link AbstractMethodDeclaration} object corresponding to the | |
* {@code IMethod}, or {@code null} if the method does not exist or | |
* is {@link org.eclipse.jdt.core.Flags#isSynthetic(int) synthetic} | |
* or is {@link org.eclipse.jdt.core.Flags#isBridge(int) bridge} or | |
* its name equals the special name <code>"<clinit>"</code> | |
* @throws JavaModelException | |
* @see org.eclipse.jdt.core.IMethod#getElementName() | |
*/ | |
protected AbstractMethodDeclaration visitMethod(final IMethod method) throws JavaModelException { | |
if (Flags.isSynthetic(method.getFlags()) || Flags.isBridge(method.getFlags()) | |
|| method.getElementName().equals("<clinit>")) { //$NON-NLS-1$ | |
return null; | |
} | |
this.currentlyVisitedJavaElement = method; | |
AbstractMethodDeclaration element = null; | |
if (method.isConstructor()) { | |
element = getFactory().createConstructorDeclaration(); | |
} else { | |
element = getFactory().createMethodDeclaration(); | |
} | |
initializeNode(element); | |
element.setName(method.getElementName()); | |
// throwns exceptions | |
for (String exc : method.getExceptionTypes()) { | |
element.getThrownExceptions().add(getRefOnType(exc)); | |
} | |
// return type | |
if (!method.isConstructor()) { | |
String returnType = method.getReturnType(); | |
((MethodDeclaration) element).setReturnType(getRefOnType(returnType)); | |
} | |
// type parameters | |
ITypeParameter[] parameters = method.getTypeParameters(); | |
for (ITypeParameter parameter : parameters) { | |
TypeParameter t = getFactory().createTypeParameter(); | |
element.getTypeParameters().add(t); | |
visitTypeParameter(parameter, t); | |
} | |
// parameters | |
for (int i = 0; i < method.getNumberOfParameters(); i++) { | |
String parameterType = method.getParameterTypes()[i]; | |
String parameterName = method.getRawParameterNames()[i]; | |
SingleVariableDeclaration var = getFactory().createSingleVariableDeclaration(); | |
initializeNode(var); | |
element.getParameters().add(var); | |
var.setMethodDeclaration(element); | |
var.setName(parameterName); | |
var.setExtraArrayDimensions(0); | |
// varargs option for the last argument | |
if (i == method.getNumberOfParameters() - 1) { | |
boolean isMethodVarargs = Flags.isVarargs(method.getFlags()); | |
var.setVarargs(isMethodVarargs); | |
} | |
var.setType(getRefOnType(parameterType)); | |
} | |
// annotations | |
for (IAnnotation annotation : method.getAnnotations()) { | |
Annotation anno = getFactory().createAnnotation(); | |
element.getAnnotations().add(anno); | |
visitAnnotation(annotation, anno); | |
} | |
// visibility modifier | |
Modifier m = getFactory().createModifier(); | |
element.setModifier(m); | |
m.setBodyDeclaration(element); | |
manageModifier(m, method.getFlags(), method); | |
ClassFileParserUtils.manageBindingDeclaration(element, method, this); | |
return element; | |
} | |
protected void visitAnnotation(final IAnnotation annotation, final Annotation anno) | |
throws JavaModelException { | |
initializeNode(anno); | |
String typeName = annotation.getElementName(); | |
// typeName is not a signature : java.lang.Deprecated | |
String typeSignature = Signature.createTypeSignature(typeName, true); | |
anno.setType(getRefOnType(typeSignature)); | |
for (IMemberValuePair valuePair : annotation.getMemberValuePairs()) { | |
AnnotationMemberValuePair element = getFactory().createAnnotationMemberValuePair(); | |
initializeNode(element); | |
anno.getValues().add(element); | |
Expression value = manageMemberValuePair(valuePair); | |
element.setValue(value); | |
// member is a method declared in an annotation | |
PendingElement pending = new PendingElement(getFactory()); | |
pending.setClientNode(element); | |
pending.setLinkName("member"); //$NON-NLS-1$ | |
Binding id = null; | |
if (this.typeFinder.isTypeExists(typeName)) { | |
ClassBinding parent = JavaModelDelegateBindingFactory.getInstance() | |
.getBindingForName(typeSignature, this, true); | |
id = new MethodBinding(); | |
((MethodBinding) id).setDeclaringClass(parent); | |
id.setName(valuePair.getMemberName()); | |
} else { | |
id = new Binding(); | |
id.setName(typeName + "." + valuePair.getMemberName() + "()"); //$NON-NLS-1$ //$NON-NLS-2$ | |
} | |
getGlobalBindings().addPending(pending, id); | |
} | |
} | |
private Expression manageMemberValuePair(final IMemberValuePair defaultValue) { | |
Expression result = null; | |
switch (defaultValue.getValueKind()) { | |
case IMemberValuePair.K_CLASS: | |
result = manageValuePairClassKind(defaultValue); | |
break; | |
case IMemberValuePair.K_ANNOTATION: | |
result = manageValuePairAnnotationKind(defaultValue); | |
break; | |
case IMemberValuePair.K_QUALIFIED_NAME: | |
result = manageValuePairQualifiedNameKind(defaultValue); | |
break; | |
case IMemberValuePair.K_BOOLEAN: | |
if (defaultValue.getValue().getClass().isArray()) { | |
Object[] tab = (Object[]) defaultValue.getValue(); | |
ArrayInitializer array = getFactory().createArrayInitializer(); | |
initializeNode(array); | |
for (Object element : tab) { | |
BooleanLiteral bool = getFactory().createBooleanLiteral(); | |
bool.setValue(((Boolean) element).booleanValue()); | |
array.getExpressions().add(bool); | |
} | |
result = array; | |
} else { | |
BooleanLiteral bool = getFactory().createBooleanLiteral(); | |
bool.setValue(((Boolean) defaultValue.getValue()).booleanValue()); | |
result = bool; | |
} | |
break; | |
case IMemberValuePair.K_CHAR: | |
if (defaultValue.getValue().getClass().isArray()) { | |
Object[] tab = (Object[]) defaultValue.getValue(); | |
ArrayInitializer array = getFactory().createArrayInitializer(); | |
initializeNode(array); | |
for (Object element : tab) { | |
CharacterLiteral ch = getFactory().createCharacterLiteral(); | |
char value = ((Character) element).charValue(); | |
ch.setEscapedValue(ClassFileParserUtils.escapeCharacter(value)); | |
array.getExpressions().add(ch); | |
} | |
result = array; | |
} else { | |
CharacterLiteral ch = getFactory().createCharacterLiteral(); | |
char value = ((Character) defaultValue.getValue()).charValue(); | |
ch.setEscapedValue(ClassFileParserUtils.escapeCharacter(value)); | |
result = ch; | |
} | |
break; | |
case IMemberValuePair.K_DOUBLE: | |
case IMemberValuePair.K_BYTE: | |
case IMemberValuePair.K_FLOAT: | |
case IMemberValuePair.K_INT: | |
case IMemberValuePair.K_LONG: | |
if (defaultValue.getValue().getClass().isArray()) { | |
Object[] tab = (Object[]) defaultValue.getValue(); | |
ArrayInitializer array = getFactory().createArrayInitializer(); | |
initializeNode(array); | |
for (Object element : tab) { | |
NumberLiteral number = getFactory().createNumberLiteral(); | |
number.setTokenValue(element.toString()); | |
array.getExpressions().add(number); | |
} | |
result = array; | |
} else { | |
NumberLiteral number = getFactory().createNumberLiteral(); | |
number.setTokenValue(defaultValue.getValue().toString()); | |
result = number; | |
} | |
break; | |
case IMemberValuePair.K_STRING: | |
if (defaultValue.getValue().getClass().isArray()) { | |
Object[] tab = (Object[]) defaultValue.getValue(); | |
ArrayInitializer array = getFactory().createArrayInitializer(); | |
initializeNode(array); | |
for (Object element : tab) { | |
StringLiteral string = getFactory().createStringLiteral(); | |
String value = String.valueOf(element); | |
string.setEscapedValue(ClassFileParserUtils.escapeString(value)); | |
array.getExpressions().add(string); | |
} | |
result = array; | |
} else { | |
StringLiteral string = getFactory().createStringLiteral(); | |
String value = String.valueOf(defaultValue.getValue()); | |
string.setEscapedValue(ClassFileParserUtils.escapeString(value)); | |
result = string; | |
} | |
break; | |
case IMemberValuePair.K_SIMPLE_NAME: // there should be no K_SIMPLE_NAME | |
// in .class files | |
case IMemberValuePair.K_UNKNOWN: | |
default: | |
if (defaultValue.getValue().getClass().isArray()) { | |
Object[] tab = (Object[]) defaultValue.getValue(); | |
ArrayInitializer array = getFactory().createArrayInitializer(); | |
initializeNode(array); | |
for (Object element : tab) { | |
UnresolvedItemAccess unrAcc = getFactory().createUnresolvedItemAccess(); | |
UnresolvedItem item = getFactory().createUnresolvedItem(); | |
unrAcc.setElement(item); | |
item.setName(String.valueOf(element)); | |
array.getExpressions().add(unrAcc); | |
} | |
result = array; | |
} else { | |
UnresolvedItemAccess unrAcc = getFactory().createUnresolvedItemAccess(); | |
UnresolvedItem item = getFactory().createUnresolvedItem(); | |
unrAcc.setElement(item); | |
item.setName(String.valueOf(defaultValue.getValue())); | |
result = unrAcc; | |
} | |
break; | |
} | |
return result; | |
} | |
private Expression manageValuePairQualifiedNameKind(final IMemberValuePair defaultValue) { | |
Expression result; | |
if (defaultValue.getValue().getClass().isArray()) { | |
Object[] tab = (Object[]) defaultValue.getValue(); | |
ArrayInitializer array = getFactory().createArrayInitializer(); | |
initializeNode(array); | |
for (Object element : tab) { | |
SingleVariableAccess varAcc = getFactory().createSingleVariableAccess(); | |
PendingElement pending = new PendingElement(getFactory()); | |
pending.setClientNode(varAcc); | |
pending.setLinkName("variable"); //$NON-NLS-1$ | |
String name = String.valueOf(element.toString()); | |
String memberName = name.substring(name.lastIndexOf('.') + 1); | |
String typeName = name.substring(0, name.lastIndexOf('.')); | |
Binding id = null; | |
if (this.typeFinder.isTypeExists(typeName)) { | |
ClassBinding parent = JavaModelDelegateBindingFactory.getInstance() | |
.getBindingForName(Signature.createTypeSignature(typeName, true), this, | |
true); | |
id = new FieldBinding(); | |
((FieldBinding) id).setDeclaringClass(parent); | |
id.setName(memberName); | |
} else { | |
id = new Binding(); | |
id.setName(typeName + "." + memberName); //$NON-NLS-1$ | |
} | |
getGlobalBindings().addPending(pending, id); | |
array.getExpressions().add(varAcc); | |
} | |
result = array; | |
} else { | |
// reference on a field or an enum constant | |
// can't use | |
// JavaModelDelegateBindingFactory.getBindingForName(String, | |
// ClassFileParser) | |
// since it is dedicated to types references | |
SingleVariableAccess varAcc = getFactory().createSingleVariableAccess(); | |
PendingElement pending = new PendingElement(getFactory()); | |
pending.setClientNode(varAcc); | |
pending.setLinkName("variable"); //$NON-NLS-1$ | |
String name = String.valueOf(defaultValue.getValue()); | |
String memberName = name.substring(name.lastIndexOf('.') + 1); | |
String typeName = name.substring(0, name.lastIndexOf('.')); | |
Binding id = null; | |
if (this.typeFinder.isTypeExists(typeName)) { | |
ClassBinding parent = JavaModelDelegateBindingFactory.getInstance() | |
.getBindingForName(Signature.createTypeSignature(typeName, true), this, | |
true); | |
id = new FieldBinding(); | |
((FieldBinding) id).setDeclaringClass(parent); | |
id.setName(memberName); | |
} else { | |
id = new Binding(); | |
id.setName(typeName + "." + memberName); //$NON-NLS-1$ | |
} | |
getGlobalBindings().addPending(pending, id); | |
result = varAcc; | |
} | |
return result; | |
} | |
private Expression manageValuePairAnnotationKind(final IMemberValuePair defaultValue) { | |
Expression result; | |
if (defaultValue.getValue().getClass().isArray()) { | |
Object[] tab = (Object[]) defaultValue.getValue(); | |
ArrayInitializer array = getFactory().createArrayInitializer(); | |
initializeNode(array); | |
for (Object element : tab) { | |
IAnnotation annotation = (IAnnotation) element; | |
Annotation anno = getFactory().createAnnotation(); | |
try { | |
visitAnnotation(annotation, anno); | |
} catch (JavaModelException e) { | |
// nothing | |
assert (true); // Dummy code for "EmptyBlock" rule | |
} | |
array.getExpressions().add(anno); | |
} | |
result = array; | |
} else { | |
IAnnotation annotation = (IAnnotation) defaultValue.getValue(); | |
Annotation anno = getFactory().createAnnotation(); | |
try { | |
visitAnnotation(annotation, anno); | |
} catch (JavaModelException e) { | |
// nothing | |
assert (true); // Dummy code for "EmptyBlock" rule | |
} | |
result = anno; | |
} | |
return result; | |
} | |
private Expression manageValuePairClassKind(final IMemberValuePair defaultValue) { | |
Expression result; | |
if (defaultValue.getValue().getClass().isArray()) { | |
Object[] tab = (Object[]) defaultValue.getValue(); | |
ArrayInitializer array = getFactory().createArrayInitializer(); | |
initializeNode(array); | |
for (Object element : tab) { | |
// the type is not a signature, we have to create one | |
String typeName = element.toString(); | |
String typeSignature = Signature.createTypeSignature(typeName, true); | |
TypeLiteral literal = getFactory().createTypeLiteral(); | |
literal.setType(getRefOnType(typeSignature)); | |
array.getExpressions().add(literal); | |
} | |
result = array; | |
} else { | |
// the type is not a signature, we have to create one | |
String typeName = defaultValue.getValue().toString(); | |
String typeSignature = Signature.createTypeSignature(typeName, true); | |
TypeLiteral literal = getFactory().createTypeLiteral(); | |
literal.setType(getRefOnType(typeSignature)); | |
result = literal; | |
} | |
return result; | |
} | |
protected void visitTypeParameter(final ITypeParameter typeParameter, | |
final TypeParameter element) throws JavaModelException { | |
initializeNode(element); | |
element.setName(typeParameter.getElementName()); | |
String[] boundsNames = typeParameter.getBounds(); | |
for (String bound : boundsNames) { | |
// bound names are not signatures | |
String boundSignature = Signature.createTypeSignature(bound, true); | |
if (!ClassFileParserUtils.isJavaLangObject(boundSignature)) { | |
element.getBounds().add(getRefOnType(boundSignature)); | |
} | |
} | |
ClassFileParserUtils.manageBindingDeclaration(element, typeParameter, this); | |
} | |
/** | |
* Handle a reference on a type. | |
* <p> | |
* Decodes the signature and tries to resolve immediately the reference. If | |
* unresolvable, a pending reference is created. | |
* </p> | |
* So, the returned {@code TypeAccess} may or may not have a resolved | |
* {@link TypeAccess#getType() type}. | |
* | |
* @param qualifiedName | |
* the signature of the referenced type (eg : [I, | |
* Ljava.lang.Object;) | |
* @return a {@code TypeAccess} | |
*/ | |
private TypeAccess getRefOnType(final String qualifiedName) { | |
TypeAccess typAcc = getFactory().createTypeAccess(); | |
switch (Signature.getTypeSignatureKind(qualifiedName)) { | |
case Signature.ARRAY_TYPE_SIGNATURE: | |
visitArrayType(typAcc, qualifiedName, this); | |
break; | |
case Signature.BASE_TYPE_SIGNATURE: | |
visitPrimitiveType(typAcc, qualifiedName); | |
break; | |
case Signature.CLASS_TYPE_SIGNATURE: | |
// a class type signature can be simple or parameterized | |
if (Signature.getTypeArguments(qualifiedName).length > 0) { | |
visitParameterizedType(typAcc, qualifiedName); // Ljava.util.List<Ljava.lang.String;>; | |
} else { | |
ClassFileParserUtils.manageBindingRef(typAcc, qualifiedName, this); // Ljava.util.List; | |
} | |
break; | |
case Signature.WILDCARD_TYPE_SIGNATURE: | |
visitWildCardType(typAcc, qualifiedName); | |
break; | |
case Signature.TYPE_VARIABLE_SIGNATURE: | |
ClassFileParserUtils.manageBindingRef(typAcc, qualifiedName, this); | |
break; | |
case Signature.CAPTURE_TYPE_SIGNATURE: | |
ClassFileParserUtils.manageBindingRef(typAcc, | |
JavaModelDelegateBindingFactory.JAVA_LANG_OBJECT_SIGNATURE, this); | |
break; | |
default: | |
// nothing | |
} | |
return typAcc; | |
} | |
protected void visitParameterizedType(final TypeAccess type, final String qualifiedName) { | |
Binding id = JavaModelDelegateBindingFactory.getInstance().getBindingForParameterizedType( | |
qualifiedName, this, false); | |
ParameterizedType parameterizedType = (ParameterizedType) getGlobalBindings().getTarget(id); | |
if (parameterizedType == null) { | |
parameterizedType = getFactory().createParameterizedType(); | |
parameterizedType.setName(id.toString()); | |
parameterizedType.setType(getRefOnType(Signature.getTypeErasure(qualifiedName))); | |
String[] typeArgumentsSignatures = Signature.getTypeArguments(qualifiedName); | |
for (String typeArgumentsSignature : typeArgumentsSignatures) { | |
parameterizedType.getTypeArguments().add(getRefOnType(typeArgumentsSignature)); | |
} | |
this.model.getOrphanTypes().add(parameterizedType); | |
getGlobalBindings().addTarget(id, parameterizedType); | |
} | |
type.setType(parameterizedType); | |
} | |
protected void visitWildCardType(final TypeAccess type, final String qualifiedName) { | |
Binding id = JavaModelDelegateBindingFactory.getInstance().getBindingForWildCardType( | |
qualifiedName, this); | |
WildCardType wildCardType = (WildCardType) getGlobalBindings().getTarget(id); | |
if (wildCardType == null) { | |
wildCardType = getFactory().createWildCardType(); | |
boolean isUpperBound = false; | |
String boundSignature = null; | |
switch (qualifiedName.charAt(0)) { | |
case Signature.C_EXTENDS: | |
isUpperBound = true; | |
break; | |
case Signature.C_SUPER: | |
boundSignature = qualifiedName.substring(1); // remove the first | |
// character | |
break; | |
case Signature.C_STAR: | |
break; | |
default: | |
break; | |
} | |
if (boundSignature != null) { | |
wildCardType.setBound(getRefOnType(boundSignature)); | |
} | |
wildCardType.setUpperBound(isUpperBound); | |
wildCardType.setName(id.toString()); | |
this.model.getOrphanTypes().add(wildCardType); | |
getGlobalBindings().addTarget(id, wildCardType); | |
} | |
type.setType(wildCardType); | |
} | |
/** | |
* @see JDTVisitorUtils#manageBindingRef(org.eclipse.jdt.core.dom.PrimitiveType, | |
* JDTVisitor) | |
*/ | |
protected void visitPrimitiveType(final TypeAccess type, final String qualifiedName) { | |
Binding id = JavaModelDelegateBindingFactory | |
.getBindingForPrimitiveType(qualifiedName, this); | |
PrimitiveType primitiveType = (PrimitiveType) getGlobalBindings().getTarget(id.toString()); | |
if (primitiveType == null) { | |
ClassFileParserUtils.initializePrimitiveTypes(getFactory(), this.model, | |
getGlobalBindings()); | |
primitiveType = (PrimitiveType) getGlobalBindings().getTarget(id.toString()); | |
} | |
if (primitiveType == null) { // should never happen | |
primitiveType = getFactory().createPrimitiveType(); | |
primitiveType.setName(id.toString()); | |
this.model.getOrphanTypes().add(primitiveType); | |
getGlobalBindings().addTarget(id, primitiveType); | |
} | |
type.setType(primitiveType); | |
} | |
/** | |
* @see JDTVisitorUtils#manageBindingRef(org.eclipse.jdt.core.dom.ArrayType, | |
* JDTVisitor) | |
*/ | |
protected void visitArrayType(final TypeAccess typAcc, final String qualifiedName, | |
final ClassFileParser visitor) { | |
Binding id = JavaModelDelegateBindingFactory.getInstance().getBindingForArrayType( | |
qualifiedName, visitor, false); | |
ArrayType arrayType = (ArrayType) getGlobalBindings().getTarget(id.toString()); | |
if (arrayType == null) { | |
arrayType = getFactory().createArrayType(); | |
arrayType.setDimensions(Signature.getArrayCount(qualifiedName)); | |
arrayType.setName(id.toString()); | |
arrayType.setElementType(getRefOnType(Signature.getElementType(qualifiedName))); | |
this.model.getOrphanTypes().add(arrayType); | |
getGlobalBindings().addTarget(id, arrayType); | |
} | |
typAcc.setType(arrayType); | |
} | |
/** | |
* Complete the MoDisco modifier with the informations of the flags. | |
* | |
* @param flags | |
* the flags | |
* @param modiscoModifier | |
* the MoDisco Modifier | |
* @see Flags | |
*/ | |
private static void manageModifier(final Modifier modiscoModifier, final int flags, | |
final IJavaElement element) { | |
int kind = element.getElementType(); | |
// static is applicable on types, methods, fields, and initializers. | |
if (!modiscoModifier.isStatic()) { | |
if (kind == IJavaElement.TYPE || kind == IJavaElement.METHOD | |
|| kind == IJavaElement.FIELD) { | |
modiscoModifier.setStatic(Flags.isStatic(flags)); | |
} | |
} | |
// native is applicable to methods | |
if (!modiscoModifier.isNative()) { | |
if (kind == IJavaElement.METHOD) { | |
modiscoModifier.setNative(Flags.isNative(flags)); | |
} | |
} | |
// strictfp is applicable to types and methods | |
if (!modiscoModifier.isStrictfp()) { | |
if (kind == IJavaElement.TYPE || kind == IJavaElement.METHOD) { | |
modiscoModifier.setStrictfp(Flags.isStrictfp(flags)); | |
} | |
} | |
// synchronized is applicable only to methods | |
if (!modiscoModifier.isSynchronized()) { | |
if (kind == IJavaElement.METHOD) { | |
modiscoModifier.setSynchronized(Flags.isSynchronized(flags)); | |
} | |
} | |
// transient is applicable only to fields | |
if (!modiscoModifier.isTransient()) { | |
if (kind == IJavaElement.FIELD) { | |
modiscoModifier.setTransient(Flags.isTransient(flags)); | |
} | |
} | |
// volatile is applicable only to fields | |
if (!modiscoModifier.isVolatile()) { | |
if (kind == IJavaElement.FIELD) { | |
modiscoModifier.setVolatile(Flags.isVolatile(flags)); | |
} | |
} | |
// visibility modifiers are applicable to types, methods, constructors, | |
// and fields. | |
if (kind == IJavaElement.TYPE || kind == IJavaElement.METHOD || kind == IJavaElement.FIELD) { | |
if (Flags.isPrivate(flags)) { | |
modiscoModifier.setVisibility(VisibilityKind.PRIVATE); | |
} else if (Flags.isProtected(flags)) { | |
modiscoModifier.setVisibility(VisibilityKind.PROTECTED); | |
} else if (Flags.isPublic(flags)) { | |
modiscoModifier.setVisibility(VisibilityKind.PUBLIC); | |
} | |
} | |
// abstract is applicable to types and methods | |
// final is applicable to types, methods and variables | |
if (kind == IJavaElement.TYPE || kind == IJavaElement.METHOD) { | |
if (Flags.isAbstract(flags)) { | |
modiscoModifier.setInheritance(InheritanceKind.ABSTRACT); | |
} else if (Flags.isFinal(flags)) { | |
modiscoModifier.setInheritance(InheritanceKind.FINAL); | |
} | |
} | |
} | |
public void setFactory(final JavaFactory factory) { | |
this.factory = factory; | |
} | |
public JavaFactory getFactory() { | |
return this.factory; | |
} | |
public void setGlobalBindings(final BindingManager globalBindings) { | |
this.globalBindings = globalBindings; | |
} | |
public BindingManager getGlobalBindings() { | |
return this.globalBindings; | |
} | |
} |