225 lines
9.0 KiB
Java
225 lines
9.0 KiB
Java
/*
|
|
* 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.
|
|
*
|
|
* This file is a derivative of code released by the University of
|
|
* California under the terms listed below.
|
|
*
|
|
* WALA JDT Frontend is Copyright (c) 2008 The Regents of the
|
|
* University of California (Regents). Provided that this notice and
|
|
* the following two paragraphs are included in any distribution of
|
|
* Refinement Analysis Tools or its derivative work, Regents agrees
|
|
* not to assert any of Regents' copyright rights in Refinement
|
|
* Analysis Tools against recipient for recipient's reproduction,
|
|
* preparation of derivative works, public display, public
|
|
* performance, distribution or sublicensing of Refinement Analysis
|
|
* Tools and derivative works, in source code and object code form.
|
|
* This agreement not to assert does not confer, by implication,
|
|
* estoppel, or otherwise any license or rights in any intellectual
|
|
* property of Regents, including, but not limited to, any patents
|
|
* of Regents or Regents' employees.
|
|
*
|
|
* IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT,
|
|
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
|
|
* INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE
|
|
* AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY
|
|
* WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING
|
|
* DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
|
|
* IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
|
|
* UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
*/
|
|
package com.ibm.wala.cast.java.translator.jdt;
|
|
|
|
import java.util.Map;
|
|
|
|
import org.eclipse.jdt.core.dom.AST;
|
|
import org.eclipse.jdt.core.dom.IMethodBinding;
|
|
import org.eclipse.jdt.core.dom.ITypeBinding;
|
|
import org.eclipse.jdt.core.dom.IVariableBinding;
|
|
|
|
import com.ibm.wala.types.ClassLoaderReference;
|
|
import com.ibm.wala.types.Descriptor;
|
|
import com.ibm.wala.types.FieldReference;
|
|
import com.ibm.wala.types.MethodReference;
|
|
import com.ibm.wala.types.Selector;
|
|
import com.ibm.wala.types.TypeName;
|
|
import com.ibm.wala.types.TypeReference;
|
|
import com.ibm.wala.util.collections.HashMapFactory;
|
|
import com.ibm.wala.util.debug.Assertions;
|
|
import com.ibm.wala.util.strings.Atom;
|
|
|
|
/**
|
|
* Class responsible for mapping JDT type system objects representing types, methods and fields to the corresponding WALA
|
|
* TypeReferences, MethodReferences and FieldReferences. Used during translation and by clients to help correlate WALA analysis
|
|
* results to the various AST nodes.
|
|
*
|
|
* In English: keeps a hashtable of WALA "type references", "field references", etc. which describe types, fields, etc. Creates
|
|
* these from their JDT equivalents and keeps the hashtable linking the two representations.
|
|
*
|
|
* @author rfuhrer
|
|
*/
|
|
public class JDTIdentityMapper {
|
|
private final Map<String, TypeReference> fTypeMap = HashMapFactory.make();
|
|
|
|
private final Map<String, FieldReference> fFieldMap = HashMapFactory.make();
|
|
|
|
private final Map<String, MethodReference> fMethodMap = HashMapFactory.make();
|
|
|
|
private final ClassLoaderReference fClassLoaderRef; // TAGALONG
|
|
|
|
private final AST fAst;
|
|
|
|
public JDTIdentityMapper(ClassLoaderReference clr, AST ast) {
|
|
fClassLoaderRef = clr;
|
|
fAst = ast;
|
|
}
|
|
|
|
// TYPES
|
|
|
|
/**
|
|
* Create (or reuse) a TypeReference for the given JDT Type Binding.<br>
|
|
* This method canonicalizes the TypeReferences
|
|
*/
|
|
public TypeReference getTypeRef(ITypeBinding type) {
|
|
type = JDT2CAstUtils.getErasedType(type, fAst); // GENERICS: erasure...
|
|
|
|
if (!fTypeMap.containsKey(type.getKey())) {
|
|
TypeName typeName = TypeName.string2TypeName(typeToTypeID(type));
|
|
TypeReference ref = TypeReference.findOrCreate(fClassLoaderRef, typeName);
|
|
|
|
fTypeMap.put(type.getKey(), ref);
|
|
return ref;
|
|
}
|
|
return fTypeMap.get(type.getKey());
|
|
}
|
|
|
|
/**
|
|
* Translates the given Polyglot type to a name suitable for use in a DOMO TypeReference (i.e. a bytecode-compliant type name).
|
|
*/
|
|
public String typeToTypeID(ITypeBinding type) {
|
|
if (type.isPrimitive())
|
|
return type.getBinaryName();
|
|
else if (type.isArray())
|
|
// arrays' binary names in JDT are like "[Ljava.lang.String;"
|
|
return type.getBinaryName().replace('.', '/').replace(";", "");
|
|
else if (type.isLocal() || type.isAnonymous())
|
|
return anonLocalTypeToTypeID(type);
|
|
else if (type.isClass() || type.isEnum() || type.isInterface()) // in polyglot interfaces are classes too. not in JDT
|
|
// class binary names in JDT are like "java.lang.String"
|
|
return 'L' + type.getBinaryName().replace('.', '/'); // TODO:
|
|
else if (type.isTypeVariable()) {
|
|
return typeToTypeID(JDT2CAstUtils.getTypesVariablesBase(type, fAst));
|
|
}
|
|
Assertions.UNREACHABLE("typeToTypeID() encountered the type " + type + " that is neither primitive, array, nor class!");
|
|
return null;
|
|
}
|
|
|
|
public String anonLocalTypeToTypeID(ITypeBinding type) {
|
|
String outerTypeID = typeToTypeID(type.getDeclaringClass());
|
|
|
|
String metSelectorName;
|
|
IMethodBinding metBinding = type.getDeclaringMethod();
|
|
if (metBinding == null) // anonymous class declared in initializer or static initializer (rare case...)
|
|
metSelectorName = "<init>";
|
|
else
|
|
metSelectorName = getMethodRef(metBinding).getSelector().toString();
|
|
|
|
String shortName = (type.isAnonymous()) ? JDT2CAstUtils.anonTypeName(type) : type.getName();
|
|
|
|
return outerTypeID + '/' + metSelectorName + '/' + shortName;
|
|
}
|
|
|
|
// FIELDS
|
|
|
|
public FieldReference getFieldRef(IVariableBinding field) {
|
|
if (!fFieldMap.containsKey(field.getKey())) {
|
|
// create one
|
|
ITypeBinding targetType = field.getDeclaringClass();
|
|
TypeReference targetTypeRef = TypeReference.findOrCreate(fClassLoaderRef, typeToTypeID(targetType));
|
|
ITypeBinding fieldType = field.getType();
|
|
TypeReference fieldTypeRef = TypeReference.findOrCreate(fClassLoaderRef, typeToTypeID(fieldType));
|
|
Atom fieldName = Atom.findOrCreateUnicodeAtom(field.getName());
|
|
FieldReference ref = FieldReference.findOrCreate(targetTypeRef, fieldName, fieldTypeRef);
|
|
|
|
fFieldMap.put(field.getKey(), ref);
|
|
return ref;
|
|
}
|
|
return fFieldMap.get(field.getKey());
|
|
}
|
|
|
|
public MethodReference fakeMethodRefNoArgs(String key, String typeID, String metName, String returnTypeID) {
|
|
if (!fMethodMap.containsKey(key)) {
|
|
// create one
|
|
TypeName ownerType = TypeName.string2TypeName(typeID);
|
|
TypeReference ownerTypeRef = TypeReference.findOrCreate(fClassLoaderRef, ownerType);
|
|
|
|
// FAKE SELECTOR
|
|
Atom name = Atom.findOrCreateUnicodeAtom(metName);
|
|
TypeName[] argTypeNames = null;
|
|
TypeName retTypeName = TypeName.string2TypeName(returnTypeID);
|
|
Descriptor desc = Descriptor.findOrCreate(argTypeNames, retTypeName);
|
|
Selector selector = new Selector(name, desc);
|
|
|
|
MethodReference ref = MethodReference.findOrCreate(ownerTypeRef, selector);
|
|
|
|
fMethodMap.put(key, ref);
|
|
return ref;
|
|
}
|
|
return fMethodMap.get(key);
|
|
}
|
|
|
|
// METHODS
|
|
public MethodReference getMethodRef(IMethodBinding met) {
|
|
if (!fMethodMap.containsKey(met.getKey())) {
|
|
// create one
|
|
TypeName ownerType = TypeName.string2TypeName(typeToTypeID(met.getDeclaringClass()));
|
|
TypeReference ownerTypeRef = TypeReference.findOrCreate(fClassLoaderRef, ownerType);
|
|
MethodReference ref = MethodReference.findOrCreate(ownerTypeRef, selectorForMethod(met));
|
|
|
|
fMethodMap.put(met.getKey(), ref);
|
|
return ref;
|
|
}
|
|
return fMethodMap.get(met.getKey());
|
|
}
|
|
|
|
private Selector selectorForMethod(IMethodBinding met) {
|
|
// TODO: have to handle default constructors?
|
|
// TODO: generics...
|
|
Atom name = (met.isConstructor()) ? MethodReference.initAtom : Atom.findOrCreateUnicodeAtom(met.getName());
|
|
|
|
TypeName[] argTypeNames = null;
|
|
ITypeBinding[] formalTypes = met.getParameterTypes();
|
|
|
|
int length = formalTypes.length;
|
|
|
|
// ENUMS: hidden name and ID in constructor
|
|
if (met.isConstructor() && met.getDeclaringClass().isEnum())
|
|
length += 2;
|
|
|
|
// Descriptor prefers null to an empty array
|
|
if (length > 0) {
|
|
argTypeNames = new TypeName[length];
|
|
int i = 0;
|
|
if (met.isConstructor() && met.getDeclaringClass().isEnum()) {
|
|
argTypeNames[0] = TypeName.string2TypeName(typeToTypeID(fAst.resolveWellKnownType("java.lang.String")));
|
|
argTypeNames[1] = TypeName.string2TypeName(typeToTypeID(fAst.resolveWellKnownType("int")));
|
|
i = 2;
|
|
}
|
|
for (ITypeBinding argType : formalTypes)
|
|
argTypeNames[i++] = TypeName.string2TypeName(typeToTypeID(argType));
|
|
}
|
|
|
|
TypeName retTypeName = TypeName.string2TypeName(typeToTypeID(met.getReturnType()));
|
|
Descriptor desc = Descriptor.findOrCreate(argTypeNames, retTypeName);
|
|
|
|
return new Selector(name, desc);
|
|
}
|
|
}
|