package ru.csu.stan.java.cfg.main;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.math.BigInteger;
import java.util.Iterator;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;
import ru.csu.stan.java.cfg.automaton.ContextFactory;
import ru.csu.stan.java.cfg.jaxb.Block;
import ru.csu.stan.java.cfg.jaxb.Call;
import ru.csu.stan.java.cfg.jaxb.Method;
import ru.csu.stan.java.cfg.jaxb.ObjectFactory;
import ru.csu.stan.java.cfg.jaxb.Project;
import ru.csu.stan.java.cfg.jaxb.Target;
import ru.csu.stan.java.cfg.jaxb.TargetClass;
import ru.csu.stan.java.cfg.util.ImportedClassIdGenerator;
import ru.csu.stan.java.cfg.util.MethodRegistry;
import ru.csu.stan.java.cfg.util.MethodRegistryItem;
import ru.csu.stan.java.cfg.util.UCFRClassNameResolver;
import ru.csu.stan.java.cfg.util.scope.ScopeRegistry;
import ru.csu.stan.java.cfg.util.scope.VariableFromScope;
import ru.csu.stan.java.cfg.util.scope.VariableScope;
import ru.csu.stan.java.classgen.automaton.IContext;
import ru.csu.stan.java.classgen.handlers.HandlerFactory;
import ru.csu.stan.java.classgen.handlers.IStaxHandler;
import ru.csu.stan.java.classgen.jaxb.Argument;
import ru.csu.stan.java.classgen.jaxb.Class;
import ru.csu.stan.java.classgen.jaxb.Classes;
import ru.csu.stan.java.classgen.util.ClassIdGenerator;
import ru.csu.stan.java.classgen.util.IClassIdGenerator;
import ru.csu.stan.java.classgen.util.ImportRegistry;
import ru.csu.stan.java.classgen.util.PackageRegistry;
/**
*
* @author mz
*
*/
public class CFGGenerator {
private IClassIdGenerator idGenerator;
private XMLInputFactory xmlFactory;
private HandlerFactory handlersFactory;
private ObjectFactory objectFactory;
private MethodRegistry cfgRegistry;
private MethodRegistry ucrRegistry;
private ImportRegistry imports;
private PackageRegistry packages;
private Classes classes;
private UCFRClassNameResolver nameResolver;
private CFGGenerator(){
xmlFactory = XMLInputFactory.newInstance();
handlersFactory = HandlerFactory.getInstance();
objectFactory = new ObjectFactory();
}
public static CFGGenerator getInstance(){
return new CFGGenerator();
}
public void importUcrIds(String inputUcr) throws JAXBException{
if (inputUcr != null && !"".equals(inputUcr)) {
JAXBContext jcontext = JAXBContext.newInstance("ru.csu.stan.java.classgen.jaxb");
Unmarshaller unmarshall = jcontext.createUnmarshaller();
classes = (Classes) unmarshall.unmarshal(new File(inputUcr));
idGenerator = ImportedClassIdGenerator.getInstanceImportClasses(classes);
importMethodregistry(classes);
}
else
idGenerator = ClassIdGenerator.getInstance();
}
private void importMethodregistry(Classes classes){
ucrRegistry = MethodRegistry.getInstance();
for (Class clazz: classes.getClazz()){
for (ru.csu.stan.java.classgen.jaxb.Method method: clazz.getMethod()){
MethodRegistryItem item = new MethodRegistryItem();
item.setName(method.getName());
item.setId(method.getId().intValue());
for (Argument arg: method.getArg())
item.addArg(arg.getName());
ucrRegistry.addMethodToRegistry(clazz.getName(), item);
}
}
}
public Project processInputFile(String filename){
Project p = firstPass(filename).getResultRoot();
secondPass(p);
thirdPass(p);
return p;
}
/**
* Первый проход генератора CFG. Создает основное дерево элементов для всех методов всех классов.
* @param filename
* @return
*/
private IContext<Project> firstPass(String filename){
this.cfgRegistry = MethodRegistry.getInstance();
this.imports = new ImportRegistry();
this.packages = new PackageRegistry();
IContext<Project> context = ContextFactory.getStartContext(objectFactory.createProject(), this.cfgRegistry, this.imports, this.packages);
try{
File f = new File(filename);
XMLEventReader reader = xmlFactory.createXMLEventReader(new FileInputStream(f));
try{
while (reader.hasNext()){
XMLEvent nextEvent = reader.nextEvent();
IStaxHandler<Project> handler = handlersFactory.createHandler(nextEvent);
context = handler.handle(context);
}
}
finally{
reader.close();
this.nameResolver = UCFRClassNameResolver.getInstance(imports, packages);
}
}
catch (FileNotFoundException e) {
System.out.println("File not found!");
e.printStackTrace();
}
catch (XMLStreamException e) {
System.out.println("Wrong XML");
e.printStackTrace();
}
return context;
}
/**
* Второй проход генератора CFG. Проставляет ID для методов.
* Устанавливает как CFG-ID, так и связанные UCR-ID.
* @param project
*/
private void secondPass(Project project){
int cfgId = 1;
for (Object o: project.getMethodOrFunction()){
if (o instanceof Method){
Method method = (Method) o;
int id = method.getUcrMethodId().intValue();
MethodRegistryItem item = cfgRegistry.getItem(method.getParentClass(), id);
MethodRegistryItem ucrItem = ucrRegistry.findSame(method.getParentClass(), item);
method.setUcrId(idGenerator.getClassId(method.getParentClass()));
method.setCfgId(BigInteger.valueOf(cfgId++));
method.setLabel(method.getParentClass());
if (ucrItem != null)
((Method) o).setUcrMethodId(BigInteger.valueOf(ucrItem.getId()));
else
((Method) o).setUcrMethodId(null);
}
}
}
/**
* Третий проход. Устанавливает id для вызовов.
* @param project
*/
private void thirdPass(Project project){
for (Object o: project.getMethodOrFunction()){
if (o instanceof Method){
Method method = (Method) o;
VariableScope rootScope = ScopeRegistry.getInstance().findScopeByClass(method.getParentClass());
for (Object bo: method.getTryExceptOrTryFinallyOrWith()){
if (bo instanceof Block){
Block block = (Block) bo;
for (Iterator<Call> it = block.getCall().iterator();it.hasNext();){
Call call = it.next();
String varName = "";
String callName = "";
if (call.getGetattr() != null){
if (call.getGetattr().getLabel().equals("this")){
String name = call.getGetattr().getName();
int dotIndex = name.indexOf('.');
if (dotIndex < 0){
varName = "this";
callName = name;
}
else{
varName = name.substring(0, dotIndex);
call.getGetattr().setLabel("this." + varName);
String leastName = name.substring(dotIndex + 1, name.length());
if (leastName.indexOf('.') < 0)
callName = leastName;
else
callName = leastName.substring(0, leastName.indexOf('.'));
call.getGetattr().setName(callName);
}
}
else{
varName = call.getGetattr().getLabel();
callName = call.getGetattr().getName();
}
}
if (call.getDirect() != null){
if (call.getDirect().getTarget() != null)
varName = "this";
else
varName = "";
callName = call.getDirect().getName();
}
VariableFromScope var = getScopedVar(varName, rootScope);
if (var == null){
var = getScopedVar(varName, rootScope);
}
String fullName = "";
if (var != null)
fullName = nameResolver.getFullTypeName(var.getType(), method.getParentClass(), this.classes);
if ("this".equals(varName))
fullName = method.getParentClass();
if ("".equals(varName))
fullName = nameResolver.getFullTypeName(callName, method.getParentClass(), this.classes);
if (fullName == null || fullName.isEmpty()){
if (call.getDirect() != null){
Target target = new ObjectFactory().createTarget();
target.setType("method");
call.getDirect().setTarget(target);
call.getDirect().setSpaceType("external");
}
}
else{
if (call.getGetattr() != null){
TargetClass tc = new ObjectFactory().createTargetClass();
tc.setUcrId(idGenerator.getClassId(fullName));
tc.setLabel(fullName);
Target target = new ObjectFactory().createTarget();
target.setCfgId(getCfgId(fullName, callName, project));
target.setType("method");
target.setTargetClass(tc);
call.getGetattr().getTarget().add(target);
}
if (call.getDirect() != null){
if ("".equals(varName)){
TargetClass tc = new ObjectFactory().createTargetClass();
tc.setUcrId(idGenerator.getClassId(fullName));
tc.setLabel(fullName);
Target target = new ObjectFactory().createTarget();
target.setCfgId(getCfgId(fullName, callName, project));
target.setType("method");
target.setTargetClass(tc);
call.getDirect().setTarget(target);
}
else{
TargetClass tc = new ObjectFactory().createTargetClass();
tc.setUcrId(method.getUcrId());
tc.setLabel(method.getParentClass());
Target target = new ObjectFactory().createTarget();
target.setCfgId(getCfgId(method.getParentClass(), callName, project));
target.setType("method");
target.setTargetClass(tc);
call.getDirect().setTarget(target);
}
}
}
}
}
}
}
}
}
private BigInteger getCfgId(String fullClassName, String call, Project project){
for (Object o: project.getMethodOrFunction()){
if (o instanceof Method){
Method method = (Method) o;
if (method.getParentClass().equals(fullClassName) && call.equals(method.getName()))
return method.getCfgId();
}
}
return null;
}
private VariableFromScope getScopedVar(String name, VariableScope rootScope){
for (VariableFromScope var: rootScope.listVars())
if (var.getName().equals(name))
return var;
for (VariableScope childScope: rootScope.listChildren()){
VariableFromScope found = getScopedVar(name, childScope);
if (found != null)
return found;
}
return null;
}
}