package org.jetbrains.ether.dependencyView;
import groovyjarjarasm.asm.Opcodes;
import org.jetbrains.ether.RW;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/**
* Created by IntelliJ IDEA.
* User: db
* Date: 01.02.11
* Time: 4:54
* To change this template use File | Settings | File Templates.
*/
public class ClassRepr extends Proto {
public final StringCache.S sourceFileName;
public final StringCache.S fileName;
public final TypeRepr.AbstractType superClass;
public final Set<TypeRepr.AbstractType> interfaces;
public final Set<TypeRepr.AbstractType> nestedClasses;
public final Set<ElementType> targets;
public final RetentionPolicy policy;
public final Set<FieldRepr> fields;
public final Set<MethodRepr> methods;
public abstract class Diff extends Difference {
public abstract Specifier<TypeRepr.AbstractType> interfaces();
public abstract Specifier<TypeRepr.AbstractType> nestedClasses();
public abstract Specifier<FieldRepr> fields();
public abstract Specifier<MethodRepr> methods();
public abstract Specifier<ElementType> targets();
public abstract boolean retentionChanged();
public abstract boolean extendsAdded ();
public boolean no() {
return base() == NONE &&
interfaces().unchanged() &&
nestedClasses().unchanged() &&
fields().unchanged() &&
methods().unchanged() &&
targets().unchanged() &&
!retentionChanged();
}
}
public Diff difference(final Proto past) {
final ClassRepr pastClass = (ClassRepr) past;
final Difference diff = super.difference(past);
int base = diff.base();
if (!superClass.equals(pastClass.superClass)) {
base |= Difference.SUPERCLASS;
}
final int d = base;
return new Diff() {
@Override
public boolean extendsAdded() {
final String pastSuperName = ((TypeRepr.ClassType) ((ClassRepr) past).superClass).className.value;
return (d & Difference.SUPERCLASS) > 0 && pastSuperName.equals("java/lang/Object");
}
@Override
public boolean packageLocalOn() {
return diff.packageLocalOn();
}
@Override
public int addedModifiers() {
return diff.addedModifiers();
}
@Override
public int removedModifiers() {
return diff.removedModifiers();
}
@Override
public Difference.Specifier<TypeRepr.AbstractType> interfaces() {
return Difference.make(pastClass.interfaces, interfaces);
}
@Override
public Difference.Specifier<TypeRepr.AbstractType> nestedClasses() {
return Difference.make(pastClass.nestedClasses, nestedClasses);
}
@Override
public Difference.Specifier<FieldRepr> fields() {
return Difference.make(pastClass.fields, fields);
}
@Override
public Difference.Specifier<MethodRepr> methods() {
return Difference.make(pastClass.methods, methods);
}
@Override
public Specifier<ElementType> targets() {
return Difference.make(pastClass.targets, targets);
}
@Override
public boolean retentionChanged() {
return !((policy == null && pastClass.policy == RetentionPolicy.CLASS) ||
(policy == RetentionPolicy.CLASS && pastClass.policy == null) ||
(policy == pastClass.policy)
);
}
@Override
public int base() {
return d;
}
};
}
public StringCache.S[] getSupers() {
final StringCache.S[] result = new StringCache.S[interfaces.size() + 1];
result[0] = ((TypeRepr.ClassType) superClass).className;
int i = 1;
for (TypeRepr.AbstractType t : interfaces) {
result[i++] = ((TypeRepr.ClassType) t).className;
}
return result;
}
public void updateClassUsages(final Set<UsageRepr.Usage> s) {
superClass.updateClassUsages(s);
for (TypeRepr.AbstractType t : interfaces) {
t.updateClassUsages(s);
}
for (MethodRepr m : methods) {
m.updateClassUsages(s);
}
for (FieldRepr f : fields) {
f.updateClassUsages(s);
}
}
public ClassRepr(final int a, final StringCache.S sn, final StringCache.S fn, final StringCache.S n, final String sig, final String sup, final String[] i, final Collection<String> ns, final Set<FieldRepr> f, final Set<MethodRepr> m, final Set<ElementType> targets, final RetentionPolicy policy) {
super(a, sig, n);
fileName = fn;
sourceFileName = sn;
superClass = TypeRepr.createClassType(sup);
interfaces = (Set<TypeRepr.AbstractType>) TypeRepr.createClassType(i, new HashSet<TypeRepr.AbstractType>());
nestedClasses = (Set<TypeRepr.AbstractType>) TypeRepr.createClassType(ns, new HashSet<TypeRepr.AbstractType>());
fields = f;
methods = m;
this.targets = targets;
this.policy = policy;
}
public ClassRepr(final BufferedReader r) {
super(r);
fileName = StringCache.get(RW.readString(r));
sourceFileName = StringCache.get(RW.readString(r));
superClass = TypeRepr.reader.read(r);
interfaces = (Set<TypeRepr.AbstractType>) RW.readMany(r, TypeRepr.reader, new HashSet<TypeRepr.AbstractType>());
nestedClasses = (Set<TypeRepr.AbstractType>) RW.readMany(r, TypeRepr.reader, new HashSet<TypeRepr.AbstractType>());
fields = (Set<FieldRepr>) RW.readMany(r, FieldRepr.reader, new HashSet<FieldRepr>());
methods = (Set<MethodRepr>) RW.readMany(r, MethodRepr.reader, new HashSet<MethodRepr>());
targets = (Set<ElementType>) RW.readMany(r, UsageRepr.AnnotationUsage.elementTypeReader, new HashSet<ElementType>());
final String s = RW.readString(r);
policy = s.isEmpty() ? null : RetentionPolicy.valueOf(s);
}
public boolean isAnnotation() {
return (access & Opcodes.ACC_ANNOTATION) > 0;
}
public static RW.Reader<ClassRepr> reader = new RW.Reader<ClassRepr>() {
public ClassRepr read(final BufferedReader r) {
return new ClassRepr(r);
}
};
public void write(final BufferedWriter w) {
super.write(w);
RW.writeln(w, fileName.value);
RW.writeln(w, sourceFileName.value);
superClass.write(w);
RW.writeln(w, interfaces);
RW.writeln(w, nestedClasses);
RW.writeln(w, fields);
RW.writeln(w, methods);
RW.writeln(w, targets, UsageRepr.AnnotationUsage.elementTypeToWritable);
RW.writeln(w, policy == null ? "" : policy.toString());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ClassRepr classRepr = (ClassRepr) o;
if (fileName != null ? !fileName.equals(classRepr.fileName) : classRepr.fileName != null) return false;
if (name != null ? !name.equals(classRepr.name) : classRepr.name != null) return false;
return true;
}
@Override
public int hashCode() {
int result = fileName != null ? fileName.hashCode() : 0;
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
public UsageRepr.Usage createUsage() {
return UsageRepr.createClassUsage(name);
}
public StringCache.S getSourceFileName() {
return sourceFileName;
}
public String getPackageName() {
return getPackageName(name);
}
public static String getPackageName(final StringCache.S s) {
return getPackageName(s.value);
}
public static String getPackageName(final String raw) {
final int index = raw.lastIndexOf('/');
if (index == -1) {
return "";
}
return raw.substring(0, index);
}
public FieldRepr findField (final StringCache.S name) {
for (FieldRepr f : fields) {
if (f.name.equals(name)) {
return f;
}
}
return null;
}
}