/*******************************************************************************
* 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.shrike.bench;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.Writer;
import com.ibm.wala.shrikeBT.Constants;
import com.ibm.wala.shrikeBT.IInstruction;
import com.ibm.wala.shrikeBT.InvokeInstruction;
import com.ibm.wala.shrikeBT.MethodData;
import com.ibm.wala.shrikeBT.Util;
import com.ibm.wala.shrikeBT.shrikeCT.ClassInstrumenter;
import com.ibm.wala.shrikeBT.shrikeCT.OfflineInstrumenter;
import com.ibm.wala.shrikeCT.ClassReader;
/**
* This is a demo class.
*
* Class files are taken as input arguments (or if there are none, from standard input). The methods in those files are
* instrumented: we insert a System.err.println() at ever method call, and a System.err.println() at every method entry.
*
* In Unix, I run it like this: java -cp ~/dev/shrike/shrike com.ibm.wala.shrikeBT.shrikeCT.tools.Bench test.jar -o output.jar
*
* The instrumented classes are placed in the directory "output" under the current directory. Disassembled code is written to the
* file "report" under the current directory.
*/
public class Statistics {
private static OfflineInstrumenter instrumenter;
public static void main(String[] args) throws Exception {
for (int i = 0; i < 1; i++) {
instrumenter = new OfflineInstrumenter(true);
Writer w = new BufferedWriter(new FileWriter("report", false));
args = instrumenter.parseStandardArgs(args);
instrumenter.beginTraversal();
ClassInstrumenter ci;
while ((ci = instrumenter.nextClass()) != null) {
doClass(ci, w);
}
instrumenter.close();
w.close();
}
}
private static void doClass(final ClassInstrumenter ci, Writer w) throws Exception {
ClassReader cr = ci.getReader();
final String className = cr.getName();
w.write("Class: " + className + "\n");
boolean allPrivateConstructors = true;
boolean methodCallsConstructor = false;
boolean classInitCallsConstructor = false;
for (int m = 0; m < cr.getMethodCount(); m++) {
MethodData d = ci.visitMethod(m);
// d could be null, e.g., if the method is abstract or native
if (d != null) {
if (d.getName().equals("<init>")) {
int f = cr.getMethodAccessFlags(m);
if ((f & Constants.ACC_PRIVATE) == 0
&& ((f & Constants.ACC_PROTECTED) == 0 || (cr.getAccessFlags() & Constants.ACC_FINAL) == 0)) {
allPrivateConstructors = false;
}
}
int constructorCalls = 0;
IInstruction[] instrs = d.getInstructions();
for (int i = 0; i < instrs.length; i++) {
if (instrs[i] instanceof InvokeInstruction) {
InvokeInstruction invoke = (InvokeInstruction) instrs[i];
if (invoke.getMethodName().equals("<init>") && invoke.getClassType().equals(Util.makeType(className))) {
constructorCalls++;
}
}
}
if (!d.getName().equals("<init>") && !d.getName().equals("<clinit>")) {
if (constructorCalls > 0) {
methodCallsConstructor = true;
}
} else if (d.getName().equals("<clinit>")) {
classInitCallsConstructor = true;
}
}
}
if (allPrivateConstructors && !methodCallsConstructor && classInitCallsConstructor) {
w.write("Restricted Creation\n");
}
}
}