/*******************************************************************************
* Copyright (c) 2010 Eric Bodden.
* 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:
* Eric Bodden - initial API and implementation
******************************************************************************/
package de.bodden.tamiflex.normalizer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.commons.EmptyVisitor;
public class ReferencedGeneratedClasses {
protected static Map<String,String> generatedClassNameToReferencedGeneratedClassName = new HashMap<String, String>();
/**
* Returns the slashed class names of all referenced generated classes, except for the declaring class itself.
*/
public synchronized static String nameOfGeneratedClassReferenced(String className, byte[] classBytes) {
String cached = generatedClassNameToReferencedGeneratedClassName.get(className);
if(cached!=null) return cached;
Set<String> res = namesOfGeneratedClassesReferenced(classBytes);
if(res.isEmpty()) return null;
if(res.size()>1) throw new RuntimeException("Class "+className+"references more than one other generated class: "+res+"\n (Current known limitation of TamiFlex.)");
//know that res has exactly one element
String ref = res.iterator().next();
//update cache
generatedClassNameToReferencedGeneratedClassName.put(className, ref);
return ref;
}
/**
* Returnes the slashed class names of all referenced generated classes, except for the declaring class itself.
*/
private static Set<String> namesOfGeneratedClassesReferenced(byte[] classBytes) {
final Set<String> res = new HashSet<String>();
ClassReader creader = new ClassReader(classBytes);
ReferencedClassesExtracter visitor = new ReferencedClassesExtracter(new EmptyVisitor(), res);
creader.accept(visitor, 0);
//remove name of the declaring class
res.remove(visitor.getClassName());
return res;
}
}