You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
737 lines
21 KiB
737 lines
21 KiB
/* ClassAnalyzer Copyright (C) 1998-2002 Jochen Hoenicke.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program; see the file COPYING.LESSER. If not, write to
|
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
package jode.decompiler;
|
|
import jode.GlobalOptions;
|
|
import jode.type.MethodType;
|
|
import jode.type.Type;
|
|
import jode.bytecode.ClassInfo;
|
|
import jode.bytecode.FieldInfo;
|
|
import jode.bytecode.MethodInfo;
|
|
import jode.bytecode.InnerClassInfo;
|
|
import jode.bytecode.ConstantPool;
|
|
import jode.expr.Expression;
|
|
import jode.expr.ThisOperator;
|
|
import jode.flow.TransformConstructors;
|
|
import jode.flow.StructuredBlock;
|
|
import jode.util.SimpleSet;
|
|
|
|
import java.lang.reflect.Modifier;
|
|
import java.util.NoSuchElementException;
|
|
import java.util.Vector;
|
|
import java.util.Enumeration;
|
|
import java.io.IOException;
|
|
|
|
import @COLLECTIONS@.Collection;
|
|
import @COLLECTIONS@.Set;
|
|
|
|
public class ClassAnalyzer
|
|
implements Scope, Declarable, ClassDeclarer
|
|
{
|
|
ImportHandler imports;
|
|
ClassInfo clazz;
|
|
ClassDeclarer parent;
|
|
ProgressListener progressListener;
|
|
|
|
/**
|
|
* The complexity for initi#alizing a class.
|
|
*/
|
|
private static double INITIALIZE_COMPLEXITY = 0.03;
|
|
/**
|
|
* The minimal visible complexity.
|
|
*/
|
|
private static double STEP_COMPLEXITY = 0.03;
|
|
/**
|
|
* The value of the strictfp modifier.
|
|
* JDK1.1 doesn't define it.
|
|
*/
|
|
private static int STRICTFP = 0x800;
|
|
|
|
double methodComplexity = 0.0;
|
|
double innerComplexity = 0.0;
|
|
|
|
String name;
|
|
StructuredBlock[] blockInitializers;
|
|
FieldAnalyzer[] fields;
|
|
MethodAnalyzer[] methods;
|
|
ClassAnalyzer[] inners;
|
|
int modifiers;
|
|
|
|
TransformConstructors constrAna;
|
|
MethodAnalyzer staticConstructor;
|
|
MethodAnalyzer[] constructors;
|
|
|
|
OuterValues outerValues;
|
|
|
|
public ClassAnalyzer(ClassDeclarer parent,
|
|
ClassInfo clazz, ImportHandler imports,
|
|
Expression[] outerValues)
|
|
{
|
|
clazz.loadInfo(clazz.MOSTINFO);
|
|
this.parent = parent;
|
|
this.clazz = clazz;
|
|
this.imports = imports;
|
|
if (outerValues != null)
|
|
this.outerValues = new OuterValues(this, outerValues);
|
|
modifiers = clazz.getModifiers();
|
|
|
|
if (parent != null) {
|
|
InnerClassInfo[] outerInfos = clazz.getOuterClasses();
|
|
if (outerInfos[0].outer == null || outerInfos[0].name == null) {
|
|
if (parent instanceof ClassAnalyzer)
|
|
throw new jode.AssertError
|
|
("ClassInfo Attributes are inconsistent: "
|
|
+ clazz.getName());
|
|
} else {
|
|
if (!(parent instanceof ClassAnalyzer)
|
|
|| !(((ClassAnalyzer) parent).clazz.getName()
|
|
.equals(outerInfos[0].outer))
|
|
|| outerInfos[0].name == null)
|
|
throw new jode.AssertError
|
|
("ClassInfo Attributes are inconsistent: "
|
|
+ clazz.getName());
|
|
}
|
|
name = outerInfos[0].name;
|
|
modifiers = outerInfos[0].modifiers;
|
|
} else {
|
|
name = clazz.getName();
|
|
int dot = name.lastIndexOf('.');
|
|
if (dot >= 0)
|
|
name = name.substring(dot+1);
|
|
}
|
|
}
|
|
|
|
public ClassAnalyzer(ClassDeclarer parent,
|
|
ClassInfo clazz, ImportHandler imports)
|
|
{
|
|
this(parent, clazz, imports, null);
|
|
}
|
|
|
|
public ClassAnalyzer(ClassInfo clazz, ImportHandler imports)
|
|
{
|
|
this(null, clazz, imports);
|
|
}
|
|
|
|
public final boolean isStatic() {
|
|
return Modifier.isStatic(modifiers);
|
|
}
|
|
|
|
public final boolean isStrictFP() {
|
|
return (modifiers & STRICTFP) != 0;
|
|
}
|
|
|
|
public FieldAnalyzer getField(int index) {
|
|
return fields[index];
|
|
}
|
|
|
|
public int getFieldIndex(String fieldName, Type fieldType) {
|
|
for (int i=0; i< fields.length; i++) {
|
|
if (fields[i].getName().equals(fieldName)
|
|
&& fields[i].getType().equals(fieldType))
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
public MethodAnalyzer getMethod(String methodName, MethodType methodType) {
|
|
for (int i=0; i< methods.length; i++) {
|
|
if (methods[i].getName().equals(methodName)
|
|
&& methods[i].getType().equals(methodType))
|
|
return methods[i];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public int getModifiers() {
|
|
return modifiers;
|
|
}
|
|
|
|
public ClassDeclarer getParent() {
|
|
return parent;
|
|
}
|
|
|
|
public void setParent(ClassDeclarer newParent) {
|
|
this.parent = newParent;
|
|
}
|
|
|
|
public ClassInfo getClazz() {
|
|
return clazz;
|
|
}
|
|
|
|
|
|
public String getName() {
|
|
return name;
|
|
}
|
|
|
|
public void setName(String name) {
|
|
this.name = name;
|
|
}
|
|
|
|
public OuterValues getOuterValues() {
|
|
return outerValues;
|
|
}
|
|
|
|
public void addBlockInitializer(int index, StructuredBlock initializer) {
|
|
if (blockInitializers[index] == null)
|
|
blockInitializers[index] = initializer;
|
|
else
|
|
blockInitializers[index].appendBlock(initializer);
|
|
}
|
|
|
|
public void initialize() {
|
|
FieldInfo[] finfos = clazz.getFields();
|
|
MethodInfo[] minfos = clazz.getMethods();
|
|
InnerClassInfo[] innerInfos = clazz.getInnerClasses();
|
|
|
|
if (finfos == null) {
|
|
/* This means that the class could not be loaded.
|
|
* give up.
|
|
*/
|
|
return;
|
|
}
|
|
|
|
if ((Options.options & Options.OPTION_INNER) != 0
|
|
&& innerInfos != null) {
|
|
/* Create inner classes */
|
|
Expression[] outerThis = new Expression[] {
|
|
new ThisOperator(clazz)
|
|
};
|
|
|
|
int innerCount = innerInfos.length;
|
|
inners = new ClassAnalyzer[innerCount];
|
|
for (int i=0; i < innerCount; i++) {
|
|
ClassInfo ci = ClassInfo.forName(innerInfos[i].inner);
|
|
inners[i] = new ClassAnalyzer
|
|
(this, ci, imports,
|
|
Modifier.isStatic(innerInfos[i].modifiers)
|
|
? null : outerThis);
|
|
}
|
|
} else
|
|
inners = new ClassAnalyzer[0];
|
|
|
|
fields = new FieldAnalyzer[finfos.length];
|
|
methods = new MethodAnalyzer[minfos.length];
|
|
blockInitializers = new StructuredBlock[finfos.length+1];
|
|
for (int j=0; j < finfos.length; j++)
|
|
fields[j] = new FieldAnalyzer(this, finfos[j], imports);
|
|
|
|
staticConstructor = null;
|
|
Vector constrVector = new Vector();
|
|
for (int j=0; j < methods.length; j++) {
|
|
methods[j] = new MethodAnalyzer(this, minfos[j], imports);
|
|
|
|
if (methods[j].isConstructor()) {
|
|
if (methods[j].isStatic())
|
|
staticConstructor = methods[j];
|
|
else
|
|
constrVector.addElement(methods[j]);
|
|
|
|
/* Java bytecode can't have strictfp modifier for
|
|
* classes, while java can't have strictfp modifier
|
|
* for constructors. We handle the difference here.
|
|
*
|
|
* If only a few constructors are strictfp and the
|
|
* methods aren't this would add too much strictfp,
|
|
* but that isn't really dangerous.
|
|
*/
|
|
if (methods[j].isStrictFP())
|
|
modifiers |= STRICTFP;
|
|
}
|
|
methodComplexity += methods[j].getComplexity();
|
|
}
|
|
|
|
constructors = new MethodAnalyzer[constrVector.size()];
|
|
constrVector.copyInto(constructors);
|
|
|
|
// initialize the inner classes.
|
|
for (int j=0; j < inners.length; j++) {
|
|
inners[j].initialize();
|
|
innerComplexity += inners[j].getComplexity();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the complexity of this class. Must be called after it has
|
|
* been initialized. This is used for a nice progress bar.
|
|
*/
|
|
public double getComplexity() {
|
|
return (methodComplexity + innerComplexity);
|
|
}
|
|
|
|
public void analyze(ProgressListener pl, double done, double scale) {
|
|
if (GlobalOptions.verboseLevel > 0)
|
|
GlobalOptions.err.println("Class " + name);
|
|
double subScale = scale / methodComplexity;
|
|
if (pl != null)
|
|
pl.updateProgress(done, name);
|
|
|
|
imports.useClass(clazz);
|
|
if (clazz.getSuperclass() != null)
|
|
imports.useClass(clazz.getSuperclass());
|
|
ClassInfo[] interfaces = clazz.getInterfaces();
|
|
for (int j=0; j< interfaces.length; j++)
|
|
imports.useClass(interfaces[j]);
|
|
|
|
if (fields == null) {
|
|
/* This means that the class could not be loaded.
|
|
* give up.
|
|
*/
|
|
return;
|
|
}
|
|
|
|
|
|
// First analyze constructors and synthetic fields:
|
|
constrAna = null;
|
|
if (constructors.length > 0) {
|
|
for (int j=0; j< constructors.length; j++)
|
|
{
|
|
if (pl != null) {
|
|
double constrCompl = constructors[j].getComplexity()
|
|
* subScale;
|
|
if (constrCompl > STEP_COMPLEXITY)
|
|
constructors[j].analyze(pl, done, constrCompl);
|
|
else {
|
|
pl.updateProgress(done, name);
|
|
constructors[j].analyze(null, 0.0, 0.0);
|
|
}
|
|
done += constrCompl;
|
|
} else
|
|
constructors[j].analyze(null, 0.0, 0.0);
|
|
}
|
|
constrAna = new TransformConstructors(this, false, constructors);
|
|
constrAna.removeSynthInitializers();
|
|
}
|
|
if (staticConstructor != null) {
|
|
if (pl != null) {
|
|
double constrCompl
|
|
= staticConstructor.getComplexity() * subScale;
|
|
if (constrCompl > STEP_COMPLEXITY)
|
|
staticConstructor.analyze(pl, done, constrCompl);
|
|
else {
|
|
pl.updateProgress(done, name);
|
|
staticConstructor.analyze(null, 0.0, 0.0);
|
|
}
|
|
done += constrCompl;
|
|
} else
|
|
staticConstructor.analyze(null, 0.0, 0.0);
|
|
}
|
|
|
|
// If output should be immediate, we delay analyzation to output.
|
|
// Note that this may break anonymous classes, but the user
|
|
// has been warned.
|
|
if ((Options.options & Options.OPTION_IMMEDIATE) != 0)
|
|
return;
|
|
|
|
// Analyze fields
|
|
for (int j=0; j < fields.length; j++)
|
|
fields[j].analyze();
|
|
|
|
// Now analyze remaining methods.
|
|
for (int j=0; j < methods.length; j++) {
|
|
if (!methods[j].isConstructor())
|
|
if (pl != null) {
|
|
double methodCompl = methods[j].getComplexity()
|
|
* subScale;
|
|
if (methodCompl > STEP_COMPLEXITY)
|
|
methods[j].analyze(pl, done, methodCompl);
|
|
else {
|
|
pl.updateProgress(done, methods[j].getName());
|
|
methods[j].analyze(null, 0.0, 0.0);
|
|
}
|
|
done += methodCompl;
|
|
} else
|
|
methods[j].analyze(null, 0.0, 0.0);
|
|
}
|
|
}
|
|
|
|
public void analyzeInnerClasses(ProgressListener pl,
|
|
double done, double scale) {
|
|
double subScale = scale / innerComplexity;
|
|
// If output should be immediate, we delay analyzation to output.
|
|
// Note that this may break anonymous classes, but the user
|
|
// has been warned.
|
|
if ((Options.options & Options.OPTION_IMMEDIATE) != 0)
|
|
return;
|
|
|
|
// Now analyze the inner classes.
|
|
for (int j=0; j < inners.length; j++) {
|
|
if (pl != null) {
|
|
double innerCompl = inners[j].getComplexity() * subScale;
|
|
if (innerCompl > STEP_COMPLEXITY) {
|
|
double innerscale = subScale * inners[j].methodComplexity;
|
|
inners[j].analyze(pl, done, innerscale);
|
|
inners[j].analyzeInnerClasses(null, done + innerscale,
|
|
innerCompl - innerscale);
|
|
} else {
|
|
pl.updateProgress(done, inners[j].name);
|
|
inners[j].analyze(null, 0.0, 0.0);
|
|
inners[j].analyzeInnerClasses(null, 0.0, 0.0);
|
|
}
|
|
done += innerCompl;
|
|
} else {
|
|
inners[j].analyze(null, 0.0, 0.0);
|
|
inners[j].analyzeInnerClasses(null, 0.0, 0.0);
|
|
}
|
|
}
|
|
|
|
// Now analyze the method scoped classes.
|
|
for (int j=0; j < methods.length; j++)
|
|
methods[j].analyzeInnerClasses();
|
|
|
|
}
|
|
|
|
public void makeDeclaration(Set done) {
|
|
if (constrAna != null)
|
|
constrAna.transform();
|
|
if (staticConstructor != null) {
|
|
new TransformConstructors
|
|
(this, true, new MethodAnalyzer[] { staticConstructor })
|
|
.transform();
|
|
}
|
|
|
|
// If output should be immediate, we delay analyzation to output.
|
|
// Note that this may break anonymous classes, but the user
|
|
// has been warned.
|
|
if ((Options.options & Options.OPTION_IMMEDIATE) != 0)
|
|
return;
|
|
|
|
for (int j=0; j < fields.length; j++)
|
|
fields[j].makeDeclaration(done);
|
|
for (int j=0; j < inners.length; j++)
|
|
inners[j].makeDeclaration(done);
|
|
for (int j=0; j < methods.length; j++)
|
|
methods[j].makeDeclaration(done);
|
|
}
|
|
|
|
public void dumpDeclaration(TabbedPrintWriter writer) throws IOException
|
|
{
|
|
dumpDeclaration(writer, null, 0.0, 0.0);
|
|
}
|
|
|
|
public void dumpDeclaration(TabbedPrintWriter writer,
|
|
ProgressListener pl, double done, double scale)
|
|
throws IOException
|
|
{
|
|
if (fields == null) {
|
|
/* This means that the class could not be loaded.
|
|
* give up.
|
|
*/
|
|
return;
|
|
}
|
|
|
|
writer.startOp(writer.NO_PAREN, 0);
|
|
/* Clear the SUPER bit, which is also used as SYNCHRONIZED bit. */
|
|
int modifiedModifiers = modifiers & ~(Modifier.SYNCHRONIZED
|
|
| STRICTFP);
|
|
if (clazz.isInterface())
|
|
/* interfaces are implicitily abstract */
|
|
modifiedModifiers &= ~Modifier.ABSTRACT;
|
|
if (parent instanceof MethodAnalyzer) {
|
|
/* method scope classes are implicitly private */
|
|
modifiedModifiers &= ~Modifier.PRIVATE;
|
|
/* anonymous classes are implicitly final */
|
|
if (name == null)
|
|
modifiedModifiers &= ~Modifier.FINAL;
|
|
}
|
|
String modif = Modifier.toString(modifiedModifiers);
|
|
if (modif.length() > 0)
|
|
writer.print(modif + " ");
|
|
if (isStrictFP()) {
|
|
/* The STRICTFP modifier is set.
|
|
* We handle it, since java.lang.reflect.Modifier is too dumb.
|
|
*/
|
|
writer.print("strictfp ");
|
|
}
|
|
/* interface is in modif */
|
|
if (!clazz.isInterface())
|
|
writer.print("class ");
|
|
writer.print(name);
|
|
ClassInfo superClazz = clazz.getSuperclass();
|
|
if (superClazz != null &&
|
|
superClazz != ClassInfo.javaLangObject) {
|
|
writer.breakOp();
|
|
writer.print(" extends " + (writer.getClassString
|
|
(superClazz, Scope.CLASSNAME)));
|
|
}
|
|
ClassInfo[] interfaces = clazz.getInterfaces();
|
|
if (interfaces.length > 0) {
|
|
writer.breakOp();
|
|
writer.print(clazz.isInterface() ? " extends " : " implements ");
|
|
writer.startOp(writer.EXPL_PAREN, 1);
|
|
for (int i=0; i < interfaces.length; i++) {
|
|
if (i > 0) {
|
|
writer.print(", ");
|
|
writer.breakOp();
|
|
}
|
|
writer.print(writer.getClassString
|
|
(interfaces[i], Scope.CLASSNAME));
|
|
}
|
|
writer.endOp();
|
|
}
|
|
writer.println();
|
|
|
|
writer.openBraceClass();
|
|
writer.tab();
|
|
dumpBlock(writer, pl, done, scale);
|
|
writer.untab();
|
|
writer.closeBraceClass();
|
|
}
|
|
|
|
public void dumpBlock(TabbedPrintWriter writer)
|
|
throws IOException
|
|
{
|
|
dumpBlock(writer, null, 0.0, 0.0);
|
|
}
|
|
|
|
public void dumpBlock(TabbedPrintWriter writer,
|
|
ProgressListener pl, double done, double scale)
|
|
throws IOException
|
|
{
|
|
double subScale = scale / getComplexity();
|
|
writer.pushScope(this);
|
|
boolean needFieldNewLine = false;
|
|
boolean needNewLine = false;
|
|
Set declared = null;
|
|
if ((Options.options & Options.OPTION_IMMEDIATE) != 0)
|
|
declared = new SimpleSet();
|
|
for (int i=0; i< fields.length; i++) {
|
|
if (blockInitializers[i] != null) {
|
|
if (needNewLine)
|
|
writer.println();
|
|
writer.openBrace();
|
|
writer.tab();
|
|
blockInitializers[i].dumpSource(writer);
|
|
writer.untab();
|
|
writer.closeBrace();
|
|
needFieldNewLine = needNewLine = true;
|
|
}
|
|
if ((Options.options & Options.OPTION_IMMEDIATE) != 0) {
|
|
// We now do the analyzation we skipped before.
|
|
fields[i].analyze();
|
|
fields[i].makeDeclaration(declared);
|
|
}
|
|
if (fields[i].skipWriting())
|
|
continue;
|
|
if (needFieldNewLine)
|
|
writer.println();
|
|
fields[i].dumpSource(writer);
|
|
needNewLine = true;
|
|
}
|
|
if (blockInitializers[fields.length] != null) {
|
|
if (needNewLine)
|
|
writer.println();
|
|
writer.openBrace();
|
|
writer.tab();
|
|
blockInitializers[fields.length].dumpSource(writer);
|
|
writer.untab();
|
|
writer.closeBrace();
|
|
needNewLine = true;
|
|
}
|
|
for (int i=0; i< inners.length; i++) {
|
|
if (needNewLine)
|
|
writer.println();
|
|
|
|
if ((Options.options & Options.OPTION_IMMEDIATE) != 0) {
|
|
// We now do the analyzation we skipped before.
|
|
inners[i].analyze(null, 0.0, 0.0);
|
|
inners[i].analyzeInnerClasses(null, 0.0, 0.0);
|
|
inners[i].makeDeclaration(declared);
|
|
}
|
|
|
|
if (pl != null) {
|
|
double innerCompl = inners[i].getComplexity() * subScale;
|
|
if (innerCompl > STEP_COMPLEXITY)
|
|
inners[i].dumpSource(writer, pl, done, innerCompl);
|
|
else {
|
|
pl.updateProgress(done, name);
|
|
inners[i].dumpSource(writer);
|
|
}
|
|
done += innerCompl;
|
|
} else
|
|
inners[i].dumpSource(writer);
|
|
needNewLine = true;
|
|
}
|
|
for (int i=0; i< methods.length; i++) {
|
|
if ((Options.options & Options.OPTION_IMMEDIATE) != 0) {
|
|
// We now do the analyzation we skipped before.
|
|
if (!methods[i].isConstructor())
|
|
methods[i].analyze(null, 0.0, 0.0);
|
|
methods[i].analyzeInnerClasses();
|
|
methods[i].makeDeclaration(declared);
|
|
}
|
|
|
|
if (methods[i].skipWriting())
|
|
continue;
|
|
if (needNewLine)
|
|
writer.println();
|
|
|
|
if (pl != null) {
|
|
double methodCompl = methods[i].getComplexity() * subScale;
|
|
pl.updateProgress(done, methods[i].getName());
|
|
methods[i].dumpSource(writer);
|
|
done += methodCompl;
|
|
} else
|
|
methods[i].dumpSource(writer);
|
|
needNewLine = true;
|
|
}
|
|
writer.popScope();
|
|
clazz.dropInfo(clazz.KNOWNATTRIBS | clazz.UNKNOWNATTRIBS);
|
|
}
|
|
|
|
public void dumpSource(TabbedPrintWriter writer)
|
|
throws IOException
|
|
{
|
|
dumpSource(writer, null, 0.0, 0.0);
|
|
}
|
|
|
|
public void dumpSource(TabbedPrintWriter writer,
|
|
ProgressListener pl, double done, double scale)
|
|
throws IOException
|
|
{
|
|
dumpDeclaration(writer, pl, done, scale);
|
|
writer.println();
|
|
}
|
|
|
|
public void dumpJavaFile(TabbedPrintWriter writer)
|
|
throws IOException {
|
|
dumpJavaFile(writer, null);
|
|
}
|
|
|
|
public void dumpJavaFile(TabbedPrintWriter writer, ProgressListener pl)
|
|
throws IOException {
|
|
imports.init(clazz.getName());
|
|
LocalInfo.init();
|
|
initialize();
|
|
double done = 0.05;
|
|
double scale = (0.75) * methodComplexity
|
|
/ (methodComplexity + innerComplexity);
|
|
analyze(pl, INITIALIZE_COMPLEXITY, scale);
|
|
done += scale;
|
|
analyzeInnerClasses(pl, done, 0.8 - done);
|
|
makeDeclaration(new SimpleSet());
|
|
imports.dumpHeader(writer);
|
|
dumpSource(writer, pl, 0.8, 0.2);
|
|
if (pl != null)
|
|
pl.updateProgress(1.0, name);
|
|
}
|
|
|
|
public boolean isScopeOf(Object obj, int scopeType) {
|
|
if (clazz.equals(obj) && scopeType == CLASSSCOPE)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
static int serialnr = 0;
|
|
public void makeNameUnique() {
|
|
name = name + "_" + serialnr++ + "_";
|
|
}
|
|
|
|
public boolean conflicts(String name, int usageType) {
|
|
return conflicts(clazz, name, usageType);
|
|
}
|
|
|
|
private static boolean conflicts(ClassInfo info,
|
|
String name, int usageType) {
|
|
while (info != null) {
|
|
if (usageType == NOSUPERMETHODNAME || usageType == METHODNAME) {
|
|
MethodInfo[] minfos = info.getMethods();
|
|
for (int i = 0; i< minfos.length; i++)
|
|
if (minfos[i].getName().equals(name))
|
|
return true;
|
|
}
|
|
if (usageType == NOSUPERFIELDNAME || usageType == FIELDNAME
|
|
|| usageType == AMBIGUOUSNAME) {
|
|
FieldInfo[] finfos = info.getFields();
|
|
for (int i=0; i < finfos.length; i++) {
|
|
if (finfos[i].getName().equals(name))
|
|
return true;
|
|
}
|
|
}
|
|
if (usageType == CLASSNAME || usageType == AMBIGUOUSNAME) {
|
|
InnerClassInfo[] iinfos = info.getInnerClasses();
|
|
if (iinfos != null) {
|
|
for (int i=0; i < iinfos.length; i++) {
|
|
if (iinfos[i].name.equals(name))
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
if (usageType == NOSUPERFIELDNAME
|
|
|| usageType == NOSUPERMETHODNAME)
|
|
return false;
|
|
|
|
ClassInfo[] ifaces = info.getInterfaces();
|
|
for (int i = 0; i < ifaces.length; i++)
|
|
if (conflicts(ifaces[i], name, usageType))
|
|
return true;
|
|
info = info.getSuperclass();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get the class analyzer for the given class info. This searches
|
|
* the method scoped/anonymous classes in this method and all
|
|
* outer methods and the outer classes for the class analyzer.
|
|
* @param cinfo the classinfo for which the analyzer is searched.
|
|
* @return the class analyzer, or null if there is not an outer
|
|
* class that equals cinfo, and not a method scope/inner class in
|
|
* an outer method.
|
|
*/
|
|
public ClassAnalyzer getClassAnalyzer(ClassInfo cinfo) {
|
|
if (cinfo == getClazz())
|
|
return this;
|
|
if (parent == null)
|
|
return null;
|
|
return getParent().getClassAnalyzer(cinfo);
|
|
}
|
|
|
|
/**
|
|
* Get the class analyzer for the given inner class.
|
|
* @param name the short name of the inner class
|
|
* @return the class analyzer, or null if there is no inner
|
|
* class with the given name.
|
|
*/
|
|
public ClassAnalyzer getInnerClassAnalyzer(String name) {
|
|
/** require name != null; **/
|
|
int innerCount = inners.length;
|
|
for (int i=0; i < innerCount; i++) {
|
|
if (inners[i].name.equals(name))
|
|
return inners[i];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* We add the named method scoped classes to the declarables.
|
|
*/
|
|
public void fillDeclarables(Collection used) {
|
|
for (int j=0; j < methods.length; j++)
|
|
methods[j].fillDeclarables(used);
|
|
}
|
|
|
|
public void addClassAnalyzer(ClassAnalyzer clazzAna) {
|
|
if (parent != null)
|
|
parent.addClassAnalyzer(clazzAna);
|
|
}
|
|
|
|
public String toString() {
|
|
return getClass().getName()+"["+getClazz()+"]";
|
|
}
|
|
}
|
|
|