mockit.internal.SuperConstructorCollector Maven / Gradle / Ivy
/*
* Copyright (c) 2006-2012 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit.internal;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import mockit.external.asm4.*;
import mockit.internal.util.*;
@SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized")
final class SuperConstructorCollector extends ClassVisitor
{
static final SuperConstructorCollector INSTANCE = new SuperConstructorCollector();
private final Map cache = new HashMap();
private String constructorDesc;
private boolean samePackage;
private SuperConstructorCollector() {}
synchronized String findConstructor(String classDesc, String superClassDesc)
{
constructorDesc = cache.get(superClassDesc);
if (constructorDesc != null) {
return constructorDesc;
}
findIfBothClassesAreInSamePackage(classDesc, superClassDesc);
ClassReader cr = createClassReader(superClassDesc);
try { cr.accept(this, ClassReader.SKIP_DEBUG); } catch (VisitInterruptedException ignore) {}
cache.put(superClassDesc, constructorDesc);
return constructorDesc;
}
private void findIfBothClassesAreInSamePackage(String classDesc, String superClassDesc)
{
int p1 = classDesc.lastIndexOf('/');
int p2 = superClassDesc.lastIndexOf('/');
samePackage = p1 == p2 && (p1 < 0 || classDesc.substring(0, p1).equals(superClassDesc.substring(0, p2)));
}
private ClassReader createClassReader(String classDesc)
{
try {
return ClassFile.readClass(classDesc);
}
catch (IOException e) {
throw new RuntimeException("Failed to read class file for " + classDesc.replace('/', '.'), e);
}
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
{
if (isAccessible(access) && "".equals(name)) {
constructorDesc = desc;
throw VisitInterruptedException.INSTANCE;
}
return null;
}
private boolean isAccessible(int access) { return access != Modifier.PRIVATE && (access != 0 || samePackage); }
}