/*******************************************************************************
* Copyright (c) 2002,2006 IBM Corporation.
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package com.ibm.wala.shrikeBT.shrikeCT;
import com.ibm.wala.shrikeBT.Constants;
import com.ibm.wala.shrikeBT.MethodData;
import com.ibm.wala.shrikeBT.analysis.ClassHierarchyStore;
import com.ibm.wala.shrikeCT.ClassReader;
import com.ibm.wala.shrikeCT.ClassWriter;
import com.ibm.wala.shrikeCT.ClassWriter.Element;
import com.ibm.wala.shrikeCT.CodeWriter;
import com.ibm.wala.shrikeCT.InvalidClassFileException;
import com.ibm.wala.shrikeCT.LineNumberTableWriter;
/**
* This is a dumping ground for useful functions that manipulate class info.
*
* @author roca@us.ibm.com
*/
public class CTUtils {
public static void addClassToHierarchy(ClassHierarchyStore store, ClassReader cr) throws InvalidClassFileException,
IllegalArgumentException {
if (store == null) {
throw new IllegalArgumentException("store is null");
}
if (cr == null) {
throw new IllegalArgumentException();
}
String[] superInterfaces = new String[cr.getInterfaceCount()];
for (int i = 0; i < superInterfaces.length; i++) {
superInterfaces[i] = CTDecoder.convertClassToType(cr.getInterfaceName(i));
}
String superName = cr.getSuperName();
if ("java/io/File".equals(cr.getName()) || "java/lang/Throwable".equals(cr.getName())) {
System.err.println(superName);
}
store.setClassInfo(CTDecoder.convertClassToType(cr.getName()), (cr.getAccessFlags() & Constants.ACC_INTERFACE) != 0, (cr
.getAccessFlags() & Constants.ACC_FINAL) != 0, superName != null ? CTDecoder.convertClassToType(superName) : null,
superInterfaces);
}
/**
* Compile and add a method to a {@link ClassWriter}.
*
* @param md the method data
* @param classWriter the target class writer
* @param rawLines line number information if available, otherwise <code>null</code>
*/
public static void compileAndAddMethodToClassWriter(MethodData md, ClassWriter classWriter, ClassWriter.Element rawLines) {
if (classWriter == null) {
throw new IllegalArgumentException("classWriter is null");
}
if (md == null) {
throw new IllegalArgumentException("md is null");
}
CTCompiler compiler = CTCompiler.make(classWriter, md);
compiler.compile();
CTCompiler.Output output = compiler.getOutput();
CodeWriter code = new CodeWriter(classWriter);
code.setMaxStack(output.getMaxStack());
code.setMaxLocals(output.getMaxLocals());
code.setCode(output.getCode());
code.setRawHandlers(output.getRawHandlers());
LineNumberTableWriter lines = null;
// I guess it is the line numbers in the java files.
if (rawLines == null) {
// add fake line numbers: just map each bytecode instruction to its own
// 'line'
// NOTE:Should not use md.getInstructions().length, because the
// the length of the created code can be smaller than the md's instruction
// length
// WRONG: int[] newLineMap = new int[md.getInstructions().length];
int[] newLineMap = new int[code.getCodeLength()];
for (int i = 0; i < newLineMap.length; i++) {
newLineMap[i] = i;
}
int[] rawTable = LineNumberTableWriter.makeRawTable(newLineMap);
lines = new LineNumberTableWriter(classWriter);
lines.setRawTable(rawTable);
}
code.setAttributes(new ClassWriter.Element[] { rawLines == null ? lines : rawLines });
Element[] elements = { code };
// System.out.println("Name:"+md.getName()+" Sig:"+md.getSignature());
classWriter.addMethod(md.getAccess(), md.getName(), md.getSignature(), elements);
}
}