blob: 68fe745ca7106196a37474a7048b3c1b6187b12e [file] [log] [blame]
/**********************************************************************
* Copyright (c) 2002, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
 *
* Contributors:
* IBM - Initial API and implementation
**********************************************************************/
package org.eclipse.wtp.releng.tools.component.internal;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.util.ClassFormatException;
import org.eclipse.jdt.core.util.IClassFileReader;
import org.eclipse.jdt.core.util.ICodeAttribute;
import org.eclipse.jdt.core.util.IConstantPool;
import org.eclipse.jdt.core.util.IConstantPoolConstant;
import org.eclipse.jdt.core.util.IConstantPoolEntry;
import org.eclipse.jdt.core.util.IFieldInfo;
import org.eclipse.jdt.core.util.ILineNumberAttribute;
import org.eclipse.jdt.core.util.IMethodInfo;
import org.eclipse.jdt.core.util.IModifierConstants;
import org.eclipse.jdt.internal.core.util.ClassFileReader;
import org.eclipse.wtp.releng.tools.component.IClazz;
import org.eclipse.wtp.releng.tools.component.ILocation;
/**
* A <code>Clazz</code> is a model object. Clazz contain references to other
* Clazz.
*/
public class Clazz implements IClazz
{
private ILocation location;
private String name;
private IClassFileReader reader;
private List methodRefs;
private List fieldRefs;
/**
* Creates a new type on the given location.
*
* @param location
*/
public Clazz(ILocation location)
{
this.location = location;
reader = null;
}
private void init()
{
if (reader == null)
{
try
{
reader = new ClassFileReader(getInputBytes(), IClassFileReader.CONSTANT_POOL | IClassFileReader.METHOD_INFOS | IClassFileReader.FIELD_INFOS | IClassFileReader.METHOD_BODIES);
}
catch (ClassFormatException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
protected byte[] getInputBytes() throws IOException
{
InputStream in = null;
byte[] fBuffer = new byte[8192];
ByteArrayOutputStream fBytesOut = new ByteArrayOutputStream(8192);
try
{
fBytesOut.reset();
in = location.getInputStream();
for (int read = in.read(fBuffer); read != -1; read = in.read(fBuffer))
{
fBytesOut.write(fBuffer, 0, read);
}
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
finally
{
in.close();
}
return fBytesOut.toByteArray();
}
/**
* @return Set a set of <code>InternalTypeReference</code> objects
*/
public Set getReferencedTypes()
{
init();
Set types = new HashSet();
IConstantPool constantPool = reader.getConstantPool();
int poolSize = constantPool.getConstantPoolCount();
for (int i = 0; i < poolSize; i++)
{
// Extract the constant's referenced class (if that is even relevant)
if (constantPool.getEntryKind(i) == IConstantPoolConstant.CONSTANT_Class)
{
IConstantPoolEntry classEntry = constantPool.decodeEntry(i);
String signature = new String(classEntry.getClassInfoName());
int index = signature.lastIndexOf('[');
if (index > -1)
{
// could be an array of a primitive type
if (signature.length() - (index + 1) == 1)
continue;
signature = Signature.toString(signature);
signature = signature.substring(0, signature.length() - 2 * (index + 1));
signature = signature.replace('.', '$');
}
String typeName = signature.replace('/', '.');
types.add(typeName);
}
}
return types;
}
public List getMethodRefs(List includes, List excludes, boolean genLineInfo)
{
if (methodRefs == null)
getRefs(includes, excludes, genLineInfo);
return methodRefs;
}
public void resetMethodRefs()
{
methodRefs = null;
}
public List getFieldRefs(List includes, List excludes, boolean genLineInfo)
{
if (fieldRefs == null)
getRefs(includes, excludes, genLineInfo);
return fieldRefs;
}
public void resetFieldRefs()
{
fieldRefs = null;
}
private void getRefs(List includes, List excludes, boolean debug)
{
methodRefs = new ArrayList(1);
fieldRefs = new ArrayList(1);
IConstantPoolEntry[] refs = getConstantPoolEntries(IConstantPoolConstant.CONSTANT_Methodref);
for (int i = 0; i < refs.length; i++)
{
if (isIncludeClass(includes, excludes, decodeClassName(refs[i].getClassName())))
{
MethodRef methodRef = new MethodRef();
methodRef.setPoolEntry(refs[i]);
methodRefs.add(methodRef);
}
}
refs = getConstantPoolEntries(IConstantPoolConstant.CONSTANT_InterfaceMethodref);
for (int i = 0; i < refs.length; i++)
{
if (isIncludeClass(includes, excludes, decodeClassName(refs[i].getClassName())))
{
MethodRef methodRef = new MethodRef();
methodRef.setPoolEntry(refs[i]);
methodRefs.add(methodRef);
}
}
refs = getConstantPoolEntries(IConstantPoolConstant.CONSTANT_Fieldref);
for (int i = 0; i < refs.length; i++)
{
if (isIncludeClass(includes, excludes, decodeClassName(refs[i].getClassName())))
{
FieldRef fieldRef = new FieldRef();
fieldRef.setPoolEntry(refs[i]);
fieldRefs.add(fieldRef);
}
}
if (debug)
{
IMethodInfo[] methodInfos = getMethodInfo();
for (int i = 0; i < methodInfos.length; i++)
{
ICodeAttribute codeAttr = methodInfos[i].getCodeAttribute();
if (codeAttr != null)
{
ILineNumberAttribute lineNumAttr = codeAttr.getLineNumberAttribute();
if (lineNumAttr != null)
{
InternalByteCodeVisitor byteCodeVisitor = new InternalByteCodeVisitor(methodRefs, fieldRefs, lineNumAttr);
try
{
codeAttr.traverse(byteCodeVisitor);
}
catch (ClassFormatException e)
{
e.printStackTrace();
}
}
}
}
}
}
/**
* @return String the fully qualified name of the type
*/
public String getName()
{
if (name == null)
{
init();
name = decodeClassName(reader.getClassName());
}
return name;
}
public String getSuperClass()
{
init();
char[] superClass = reader.getSuperclassName();
if (superClass != null)
return decodeClassName(superClass);
else
return null;
}
public String[] getInterfaces()
{
init();
char[][] interfaceNames = reader.getInterfaceNames();
String[] interfaces = new String[interfaceNames.length];
for (int i = 0; i < interfaces.length; i++)
interfaces[i] = decodeClassName(interfaceNames[i]);
return interfaces;
}
public IFieldInfo[] getFieldInfo()
{
init();
return reader.getFieldInfos();
}
public IMethodInfo[] getMethodInfo()
{
init();
return reader.getMethodInfos();
}
public IConstantPoolEntry[] getConstantPoolEntries(int kind)
{
init();
List entries = new Vector();
IConstantPool pool = reader.getConstantPool();
int poolSize = pool.getConstantPoolCount();
for (int i = 0; i < poolSize; i++)
if (pool.getEntryKind(i) == kind)
entries.add(pool.decodeEntry(i));
return (IConstantPoolEntry[])entries.toArray(new IConstantPoolEntry[0]);
}
public boolean isInterface()
{
init();
return ((reader.getAccessFlags() & IModifierConstants.ACC_INTERFACE) == IModifierConstants.ACC_INTERFACE);
}
public int getAccessFlags()
{
init();
return reader.getAccessFlags();
}
private String decodeClassName(char[] name)
{
return new String(name).replace('/', '.');
}
private boolean isIncludeClass(List classIncludes, List classExcludes, String className)
{
if (classExcludes != null)
for (Iterator it = classExcludes.iterator(); it.hasNext();)
if (className.startsWith((String)it.next()))
return false;
if (classIncludes != null && classIncludes.size() > 0)
{
for (Iterator it = classIncludes.iterator(); it.hasNext();)
if (className.startsWith((String)it.next()))
return true;
return false;
}
return true;
}
public void resetClazz()
{
reader = null;
methodRefs = null;
fieldRefs = null;
}
}