[proguard] 01/02: Imported Upstream version 3.3.2

Emmanuel Bourg ebourg-guest at moszumanska.debian.org
Thu Apr 10 09:00:32 UTC 2014


This is an automated email from the git hooks/post-receive script.

ebourg-guest pushed a commit to annotated tag debian/3.3.2-1
in repository proguard.

commit 1058f05e9ab6ab40d34a5602c165395c36592e58
Author: Sam Clegg <samo at debian.org>
Date:   Thu Apr 10 10:41:52 2014 +0200

    Imported Upstream version 3.3.2
---
 README                                             |   8 +-
 docs/FAQ.html                                      |  36 +-
 docs/GPL_exception.html                            |  16 +-
 docs/acknowledgements.html                         |   4 +-
 docs/alternatives.html                             | 179 +++---
 docs/downloads.html                                |  26 +-
 docs/feedback.html                                 |  20 +-
 docs/license.html                                  |  42 +-
 docs/main.html                                     |   2 +-
 docs/manual/ant.html                               |  14 +-
 docs/manual/examples.html                          |   6 +-
 docs/manual/gui.html                               |   7 +-
 docs/manual/index.html                             |   2 +-
 docs/manual/introduction.html                      |   6 +-
 docs/manual/limitations.html                       |  18 +-
 docs/manual/refcard.html                           |  15 +-
 docs/manual/retrace/examples.html                  |   2 +-
 docs/manual/retrace/index.html                     |   2 +-
 docs/manual/retrace/introduction.html              |   2 +-
 docs/manual/retrace/usage.html                     |   2 +-
 docs/manual/troubleshooting.html                   |  65 +-
 docs/manual/usage.html                             |  45 +-
 docs/manual/wtk.html                               |   2 +-
 docs/quality.html                                  |   2 +-
 docs/results.html                                  |   2 +-
 docs/screenshots.html                              |   2 +-
 docs/testimonials.html                             |   2 +-
 docs/title.html                                    |   2 +-
 examples/ant/proguard.xml                          |   2 +-
 examples/proguard.pro                              |   2 +-
 examples/proguardall.pro                           |   2 +-
 examples/proguardgui.pro                           |   8 +-
 examples/retrace.pro                               |   8 +-
 lib/proguard.jar                                   | Bin 0 -> 394065 bytes
 lib/proguardgui.jar                                | Bin 0 -> 123885 bytes
 lib/retrace.jar                                    | Bin 0 -> 5110 bytes
 src/proguard/ArgumentWordReader.java               |  49 +-
 src/proguard/ClassMemberSpecification.java         |   4 +-
 src/proguard/ClassPath.java                        |   4 +-
 src/proguard/ClassPathEntry.java                   |  37 +-
 src/proguard/ClassSpecification.java               |   4 +-
 src/proguard/Configuration.java                    |  41 +-
 src/proguard/ConfigurationConstants.java           |   4 +-
 src/proguard/ConfigurationParser.java              | 177 ++++--
 src/proguard/ConfigurationWriter.java              |  81 ++-
 src/proguard/DataEntryReaderFactory.java           |   4 +-
 src/proguard/DataEntryWriterFactory.java           |   8 +-
 src/proguard/FileWordReader.java                   |  54 +-
 src/proguard/GPL.java                              | 184 ++++++
 src/proguard/ParseException.java                   |   4 +-
 src/proguard/ProGuard.java                         | 467 +++++++++++---
 src/proguard/SubclassedClassFileFilter.java        |   4 +-
 src/proguard/WordReader.java                       |  62 +-
 .../ant/ClassMemberSpecificationElement.java       |   4 +-
 src/proguard/ant/ClassPathElement.java             |  25 +-
 src/proguard/ant/ClassSpecificationElement.java    |   4 +-
 src/proguard/ant/ConfigurationElement.java         |   4 +-
 src/proguard/ant/ConfigurationTask.java            |  44 +-
 src/proguard/ant/KeepAttributeElement.java         |   4 +-
 src/proguard/ant/ProGuardTask.java                 |  61 +-
 src/proguard/classfile/ClassConstants.java         |  98 +--
 src/proguard/classfile/ClassCpInfo.java            |   4 +-
 src/proguard/classfile/ClassFile.java              |  98 ++-
 src/proguard/classfile/ClassPool.java              |  11 +-
 src/proguard/classfile/CpInfo.java                 |   4 +-
 src/proguard/classfile/DoubleCpInfo.java           |   4 +-
 src/proguard/classfile/FieldInfo.java              |   4 +-
 src/proguard/classfile/FieldrefCpInfo.java         |   4 +-
 src/proguard/classfile/FloatCpInfo.java            |   4 +-
 src/proguard/classfile/IntegerCpInfo.java          |   4 +-
 .../classfile/InterfaceMethodrefCpInfo.java        |   4 +-
 src/proguard/classfile/LibraryClassFile.java       | 261 ++++++--
 src/proguard/classfile/LibraryFieldInfo.java       |  20 +-
 src/proguard/classfile/LibraryMemberInfo.java      |   4 +-
 src/proguard/classfile/LibraryMethodInfo.java      |  20 +-
 src/proguard/classfile/LongCpInfo.java             |   4 +-
 src/proguard/classfile/MemberInfo.java             |   4 +-
 src/proguard/classfile/MethodInfo.java             |   4 +-
 src/proguard/classfile/MethodrefCpInfo.java        |   4 +-
 src/proguard/classfile/NameAndTypeCpInfo.java      |  49 +-
 src/proguard/classfile/ProgramClassFile.java       | 281 +++++++--
 src/proguard/classfile/ProgramFieldInfo.java       |  22 +-
 src/proguard/classfile/ProgramMemberInfo.java      |  35 +-
 src/proguard/classfile/ProgramMethodInfo.java      |  28 +-
 src/proguard/classfile/RefCpInfo.java              |   4 +-
 src/proguard/classfile/StringCpInfo.java           |   4 +-
 src/proguard/classfile/Utf8CpInfo.java             |   4 +-
 src/proguard/classfile/VisitorAccepter.java        |   4 +-
 .../classfile/attribute/AllAttrInfoVisitor.java    |  67 +-
 src/proguard/classfile/attribute/AttrInfo.java     |   4 +-
 .../classfile/attribute/AttrInfoVisitor.java       |   5 +-
 src/proguard/classfile/attribute/CodeAttrInfo.java |   8 +-
 .../classfile/attribute/DeprecatedAttrInfo.java    |   4 +-
 .../attribute/EnclosingMethodAttrInfo.java         |   4 +-
 .../classfile/attribute/ExceptionInfo.java         |   4 +-
 .../classfile/attribute/ExceptionInfoVisitor.java  |   4 +-
 .../classfile/attribute/ExceptionsAttrInfo.java    |   4 +-
 .../classfile/attribute/InnerClassesAttrInfo.java  |   4 +-
 .../classfile/attribute/InnerClassesInfo.java      |   4 +-
 .../attribute/InnerClassesInfoVisitor.java         |   4 +-
 .../classfile/attribute/LibraryAttrInfo.java       |   4 +-
 .../classfile/attribute/LineNumberInfo.java        |   4 +-
 .../attribute/LineNumberTableAttrInfo.java         |   4 +-
 .../classfile/attribute/LocalVariableInfo.java     |   4 +-
 .../attribute/LocalVariableInfoVisitor.java        |   4 +-
 .../attribute/LocalVariableTableAttrInfo.java      |   4 +-
 .../classfile/attribute/LocalVariableTypeInfo.java |   4 +-
 .../attribute/LocalVariableTypeInfoVisitor.java    |   4 +-
 .../attribute/LocalVariableTypeTableAttrInfo.java  |   4 +-
 .../classfile/attribute/MultiAttrInfoVisitor.java  |   4 +-
 .../classfile/attribute/SignatureAttrInfo.java     |   4 +-
 .../classfile/attribute/SourceDirAttrInfo.java     |   4 +-
 .../classfile/attribute/SourceFileAttrInfo.java    |   4 +-
 .../classfile/attribute/SyntheticAttrInfo.java     |   4 +-
 .../classfile/attribute/UnknownAttrInfo.java       |   4 +-
 .../classfile/attribute/annotation/Annotation.java |   4 +-
 .../annotation/AnnotationDefaultAttrInfo.java      |   4 +-
 .../annotation/AnnotationElementValue.java         |   4 +-
 .../attribute/annotation/AnnotationVisitor.java    |   4 +-
 .../attribute/annotation/ArrayElementValue.java    |   4 +-
 .../attribute/annotation/ClassElementValue.java    |   4 +-
 .../attribute/annotation/ConstantElementValue.java |   4 +-
 .../attribute/annotation/ElementValue.java         |  13 +-
 .../attribute/annotation/ElementValueVisitor.java  |   4 +-
 .../annotation/EnumConstantElementValue.java       |   4 +-
 .../annotation/RuntimeAnnotationsAttrInfo.java     |   4 +-
 .../RuntimeInvisibleAnnotationsAttrInfo.java       |   4 +-
 ...ntimeInvisibleParameterAnnotationsAttrInfo.java |   4 +-
 .../RuntimeParameterAnnotationsAttrInfo.java       |  59 +-
 .../RuntimeVisibleAnnotationsAttrInfo.java         |   4 +-
 ...RuntimeVisibleParameterAnnotationsAttrInfo.java |   4 +-
 .../classfile/editor/ClassFileReferenceFixer.java  | 495 +++++++++++++++
 .../classfile/editor/CodeAttrInfoEditor.java       | 167 +++--
 .../editor/CodeAttrInfoEditorResetter.java         |   4 +-
 .../classfile/editor/ComparableCpInfo.java         |   4 +-
 .../classfile/editor/ConstantPoolEditor.java       | 328 ++++++----
 .../classfile/editor/ConstantPoolRemapper.java     |  27 +-
 .../classfile/editor/ConstantPoolSorter.java       |   4 +-
 .../classfile/editor/MemberReferenceFixer.java     | 469 ++++++++++++++
 .../classfile/editor/MethodInvocationFixer.java    | 284 +++++++++
 .../classfile/editor/StackSizeUpdater.java         |  14 +-
 .../editor/VariableEditor.java}                    | 162 ++---
 .../classfile/editor/VariableRemapper.java         | 223 +++++++
 .../classfile/instruction/BranchInstruction.java   |   4 +-
 .../classfile/instruction/CpInstruction.java       |   4 +-
 .../classfile/instruction/Instruction.java         |   4 +-
 .../classfile/instruction/InstructionFactory.java  |   4 +-
 .../classfile/instruction/InstructionVisitor.java  |   4 +-
 .../instruction/LookUpSwitchInstruction.java       |   4 +-
 .../instruction/MultiInstructionVisitor.java       |  28 +-
 .../classfile/instruction/SimpleInstruction.java   |   4 +-
 .../instruction/TableSwitchInstruction.java        |   4 +-
 .../classfile/instruction/VariableInstruction.java |  49 +-
 src/proguard/classfile/util/AccessUtil.java        |   9 +-
 .../ClassFileClassForNameReferenceInitializer.java |  68 +-
 .../util/ClassFileHierarchyInitializer.java        |   8 +-
 .../util/ClassFileReferenceInitializer.java        | 116 ++--
 .../classfile/util/ClassForNameChecker.java        |   4 +-
 .../classfile/util/ClassNewInstanceChecker.java    |   4 +-
 src/proguard/classfile/util/ClassUtil.java         |  31 +-
 .../classfile/util/DescriptorClassEnumeration.java |  22 +-
 .../classfile/util/ExternalTypeEnumeration.java    |   4 +-
 .../classfile/util/InternalTypeEnumeration.java    |   4 +-
 src/proguard/classfile/util/MemberFinder.java      |  36 +-
 .../util/MethodInfoLinker.java}                    |  80 +--
 .../classfile/visitor/AllClassFileVisitor.java     |   4 +-
 .../classfile/visitor/AllCpInfoVisitor.java        |   4 +-
 .../classfile/visitor/AllFieldVisitor.java         |   4 +-
 .../classfile/visitor/AllMemberInfoVisitor.java    |   4 +-
 .../classfile/visitor/AllMethodVisitor.java        |   4 +-
 .../classfile/visitor/BottomClassFileFilter.java   |   4 +-
 .../classfile/visitor/ClassFileAccessFilter.java   |   4 +-
 .../classfile/visitor/ClassFileCleaner.java        |   4 +-
 .../visitor/ClassFileHierarchyTraveler.java        |   4 +-
 .../visitor/ClassFileMemberInfoVisitor.java        |   4 +-
 .../classfile/visitor/ClassFileNameFilter.java     |   4 +-
 .../classfile/visitor/ClassFilePrinter.java        |   4 +-
 .../classfile/visitor/ClassFileVisitor.java        |   4 +-
 .../classfile/visitor/ClassPoolFiller.java         |   4 +-
 .../classfile/visitor/ClassPoolVisitor.java        |   4 +-
 .../visitor/ConcreteClassFileDownTraveler.java     |   4 +-
 src/proguard/classfile/visitor/CpInfoVisitor.java  |   4 +-
 .../classfile/visitor/LibraryClassFileFilter.java  |   4 +-
 .../classfile/visitor/LibraryMemberInfoFilter.java |   4 +-
 .../classfile/visitor/LineNumberInfoVisitor.java   |   4 +-
 .../classfile/visitor/MemberInfoAccessFilter.java  |   4 +-
 .../visitor/MemberInfoDescriptorFilter.java        |   4 +-
 .../classfile/visitor/MemberInfoNameFilter.java    |   4 +-
 .../classfile/visitor/MemberInfoVisitor.java       |   4 +-
 ...Filter.java => MethodImplementationFilter.java} |  38 +-
 ...lter.java => MethodImplementationTraveler.java} |  40 +-
 .../classfile/visitor/MultiClassFileVisitor.java   |   4 +-
 .../classfile/visitor/MultiMemberInfoVisitor.java  |   4 +-
 .../classfile/visitor/NamedClassFileVisitor.java   |   4 +-
 .../classfile/visitor/NamedFieldVisitor.java       |   4 +-
 .../classfile/visitor/NamedMethodVisitor.java      |   4 +-
 .../classfile/visitor/ProgramClassFileFilter.java  |   4 +-
 .../classfile/visitor/ProgramMemberInfoFilter.java |   4 +-
 .../visitor/ReferencedClassFileVisitor.java        |  11 +-
 .../classfile/visitor/SimpleClassFilePrinter.java  |   4 +-
 .../visitor/VariableClassFileVisitor.java          |   4 +-
 .../visitor/VariableMemberInfoVisitor.java         |   4 +-
 .../gui/ClassMemberSpecificationDialog.java        |   6 +-
 .../gui/ClassMemberSpecificationsPanel.java        |   4 +-
 src/proguard/gui/ClassPathPanel.java               |  10 +-
 src/proguard/gui/ClassSpecificationDialog.java     |   6 +-
 src/proguard/gui/ClassSpecificationsPanel.java     |   4 +-
 src/proguard/gui/ExtensionFileFilter.java          |   4 +-
 src/proguard/gui/FilterDialog.java                 |   6 +-
 src/proguard/gui/GUIResources.java                 |   4 +-
 src/proguard/gui/GUIResources.properties           |   7 +-
 src/proguard/gui/ListPanel.java                    |   4 +-
 src/proguard/gui/MessageDialogRunnable.java        |   4 +-
 src/proguard/gui/ProGuardGUI.java                  | 187 +++---
 src/proguard/gui/ProGuardRunnable.java             |   9 +-
 src/proguard/gui/ReTraceRunnable.java              |  20 +-
 src/proguard/gui/SwingUtil.java                    |   4 +-
 src/proguard/gui/TabbedPane.java                   |   4 +-
 src/proguard/gui/TextAreaOutputStream.java         |   4 +-
 src/proguard/gui/splash/BufferedSprite.java        |   4 +-
 src/proguard/gui/splash/CircleSprite.java          |   4 +-
 src/proguard/gui/splash/ClipSprite.java            |   4 +-
 src/proguard/gui/splash/CompositeSprite.java       |   4 +-
 src/proguard/gui/splash/ImageSprite.java           |   4 +-
 src/proguard/gui/splash/LinearColor.java           |   4 +-
 src/proguard/gui/splash/LinearDouble.java          |   4 +-
 src/proguard/gui/splash/LinearInt.java             |   4 +-
 src/proguard/gui/splash/LinearTiming.java          |   4 +-
 src/proguard/gui/splash/OverrideGraphics2D.java    |   4 +-
 src/proguard/gui/splash/RectangleSprite.java       |   4 +-
 src/proguard/gui/splash/SawToothTiming.java        |   4 +-
 src/proguard/gui/splash/ShadowedSprite.java        |   4 +-
 src/proguard/gui/splash/SineTiming.java            |   4 +-
 src/proguard/gui/splash/SmoothTiming.java          |   4 +-
 src/proguard/gui/splash/SplashPanel.java           |   4 +-
 src/proguard/gui/splash/Sprite.java                |   4 +-
 src/proguard/gui/splash/TextSprite.java            |   4 +-
 src/proguard/gui/splash/TimeSwitchSprite.java      |   4 +-
 src/proguard/gui/splash/Timing.java                |   4 +-
 src/proguard/gui/splash/TypeWriterString.java      |   4 +-
 src/proguard/gui/splash/VariableColor.java         |   4 +-
 src/proguard/gui/splash/VariableDouble.java        |   4 +-
 src/proguard/gui/splash/VariableFont.java          |   4 +-
 src/proguard/gui/splash/VariableInt.java           |   4 +-
 src/proguard/gui/splash/VariableSizeFont.java      |   4 +-
 src/proguard/gui/splash/VariableString.java        |   4 +-
 src/proguard/io/CascadingDataEntryWriter.java      |   4 +-
 src/proguard/io/ClassFileFilter.java               |   4 +-
 src/proguard/io/ClassFileReader.java               |  14 +-
 src/proguard/io/ClassFileRewriter.java             |   4 +-
 src/proguard/io/DataEntry.java                     |   4 +-
 src/proguard/io/DataEntryCopier.java               |   4 +-
 src/proguard/io/DataEntryPump.java                 |   4 +-
 src/proguard/io/DataEntryReader.java               |   4 +-
 src/proguard/io/DataEntryWriter.java               |   4 +-
 src/proguard/io/DirectoryPump.java                 |   4 +-
 src/proguard/io/DirectoryWriter.java               |   4 +-
 src/proguard/io/FileDataEntry.java                 |   4 +-
 src/proguard/io/FilteredDataEntryReader.java       |   4 +-
 src/proguard/io/FilteredDataEntryWriter.java       |   4 +-
 src/proguard/io/Finisher.java                      |   4 +-
 src/proguard/io/JarReader.java                     |   4 +-
 src/proguard/io/JarWriter.java                     |   4 +-
 src/proguard/io/ParentDataEntryWriter.java         |   4 +-
 src/proguard/io/RenamedDataEntry.java              |   4 +-
 src/proguard/io/ZipDataEntry.java                  |   4 +-
 src/proguard/obfuscate/AttributeShrinker.java      |   4 +-
 src/proguard/obfuscate/AttributeUsageMarker.java   |   4 +-
 src/proguard/obfuscate/ClassFileObfuscator.java    |   4 +-
 src/proguard/obfuscate/ClassFileOpener.java        | 117 ++++
 src/proguard/obfuscate/ClassFileRenamer.java       | 683 ++-------------------
 ...NameFactory.java => DictionaryNameFactory.java} |  19 +-
 .../MapCleaner.java}                               |  30 +-
 src/proguard/obfuscate/MappingKeeper.java          |   8 +-
 src/proguard/obfuscate/MappingPrinter.java         |  74 +--
 src/proguard/obfuscate/MappingProcessor.java       |   4 +-
 src/proguard/obfuscate/MappingReader.java          |  12 +-
 .../MemberInfoNameCleaner.java}                    |  35 +-
 .../obfuscate/MemberInfoNameCollector.java         | 132 ++++
 .../MemberInfoNameConflictFilter.java}             |  76 +--
 src/proguard/obfuscate/MemberInfoObfuscator.java   | 436 +++++--------
 .../MemberInfoSpecialNameFilter.java}              |  50 +-
 src/proguard/obfuscate/MultiMappingProcessor.java  |   4 +-
 src/proguard/obfuscate/NameAndTypeShrinker.java    |   4 +-
 src/proguard/obfuscate/NameAndTypeUsageMarker.java |   4 +-
 src/proguard/obfuscate/NameFactory.java            |   4 +-
 .../NameFactoryResetter.java}                      |  28 +-
 src/proguard/obfuscate/NameMarker.java             |  67 +-
 src/proguard/obfuscate/SimpleNameFactory.java      |   4 +-
 .../SourceFileRenamer.java}                        |  66 +-
 src/proguard/obfuscate/SpecialNameFactory.java     |  86 +++
 src/proguard/obfuscate/Utf8Shrinker.java           |   4 +-
 src/proguard/obfuscate/Utf8UsageMarker.java        |   4 +-
 src/proguard/optimize/ChangedCodePrinter.java      |   4 +-
 src/proguard/optimize/KeepMarker.java              |  18 +-
 src/proguard/optimize/MethodOptimizationInfo.java  | 114 ++++
 .../MethodOptimizationInfoSetter.java}             |  44 +-
 .../optimize/NoSideEffectMethodMarker.java         |  28 +-
 src/proguard/optimize/NonPrivateMethodMarker.java  | 141 +++++
 src/proguard/optimize/ParameterShrinker.java       | 322 ++++++++++
 src/proguard/optimize/ParameterUsageMarker.java    | 138 +++++
 .../optimize/SideEffectInstructionChecker.java     |  79 +--
 src/proguard/optimize/SideEffectMethodMarker.java  |  26 +-
 .../NopRemover.java => VariableUsageMarker.java}   |  60 +-
 src/proguard/optimize/WriteOnlyFieldMarker.java    |   4 +-
 src/proguard/optimize/evaluation/BranchUnit.java   |   4 +-
 .../optimize/evaluation/PartialEvaluator.java      | 410 ++++++++-----
 src/proguard/optimize/evaluation/Processor.java    |   4 +-
 src/proguard/optimize/evaluation/Stack.java        |  30 +-
 .../optimize/evaluation/TracedBranchUnit.java      |   6 +-
 src/proguard/optimize/evaluation/TracedStack.java  |  30 +-
 .../optimize/evaluation/TracedVariables.java       |  50 +-
 .../UnusedParameterCleaner.java}                   | 166 ++---
 src/proguard/optimize/evaluation/Variables.java    |   4 +-
 .../optimize/evaluation/value/Category1Value.java  |   4 +-
 .../optimize/evaluation/value/Category2Value.java  |   4 +-
 .../optimize/evaluation/value/DoubleValue.java     |   4 +-
 .../evaluation/value/DoubleValueFactory.java       |   4 +-
 .../optimize/evaluation/value/FloatValue.java      |   4 +-
 .../evaluation/value/FloatValueFactory.java        |   4 +-
 .../evaluation/value/InstructionOffsetValue.java   |   4 +-
 .../value/InstructionOffsetValueFactory.java       |   4 +-
 .../optimize/evaluation/value/IntegerValue.java    |   4 +-
 .../evaluation/value/IntegerValueFactory.java      |   4 +-
 .../optimize/evaluation/value/LongValue.java       |   4 +-
 .../evaluation/value/LongValueFactory.java         |   4 +-
 .../optimize/evaluation/value/ReferenceValue.java  |   4 +-
 .../evaluation/value/ReferenceValueFactory.java    |   7 +-
 .../value/SpecificArrayReferenceValue.java         |   4 +-
 .../evaluation/value/SpecificDoubleValue.java      |   4 +-
 .../evaluation/value/SpecificFloatValue.java       |   4 +-
 .../evaluation/value/SpecificIntegerValue.java     |   4 +-
 .../evaluation/value/SpecificLongValue.java        |   4 +-
 .../evaluation/value/SpecificReferenceValue.java   |   4 +-
 src/proguard/optimize/evaluation/value/Value.java  |   4 +-
 .../optimize/evaluation/value/ValueFactory.java    |   4 +-
 .../optimize/peephole/BranchTargetFinder.java      |   4 +-
 .../optimize/peephole/ClassFileFinalizer.java      |  16 +-
 .../optimize/peephole/GetterSetterInliner.java     |  60 +-
 .../optimize/peephole/GotoReturnReplacer.java      |   4 +-
 .../optimize/peephole/LoadStoreRemover.java        |  12 +-
 .../MethodPrivatizer.java}                         |  58 +-
 src/proguard/optimize/peephole/NopRemover.java     |   4 +-
 src/proguard/optimize/peephole/PushPopRemover.java |   4 +-
 .../peephole/SingleImplementationFixer.java        | 181 ++++++
 .../peephole/SingleImplementationInliner.java      | 523 +++++-----------
 .../peephole/SingleImplementationMarker.java       |  38 +-
 .../optimize/peephole/StoreLoadReplacer.java       |   9 +-
 src/proguard/retrace/ReTrace.java                  |  56 +-
 src/proguard/retrace/StackTrace.java               |  12 +-
 src/proguard/retrace/StackTraceItem.java           |   6 +-
 src/proguard/shrink/ClassFileShrinker.java         |  31 +-
 src/proguard/shrink/InnerUsageMarker.java          |  36 +-
 src/proguard/shrink/InterfaceUsageMarker.java      |  35 +-
 src/proguard/shrink/ShortestUsageMark.java         | 183 ++++++
 src/proguard/shrink/ShortestUsageMarker.java       | 264 ++++++++
 src/proguard/shrink/ShortestUsagePrinter.java      | 210 +++++++
 src/proguard/shrink/UsageMarker.java               | 293 +++++----
 src/proguard/shrink/UsagePrinter.java              |  29 +-
 src/proguard/shrink/UsedClassFileFilter.java       |  22 +-
 src/proguard/util/BasicMatcher.java                |  14 +-
 src/proguard/util/ExtensionMatcher.java            |   4 +-
 src/proguard/util/FileNameMatcher.java             |   3 +-
 src/proguard/util/ListUtil.java                    |   4 +-
 src/proguard/wtk/ProGuardObfuscator.java           |  25 +-
 365 files changed, 8491 insertions(+), 3953 deletions(-)

diff --git a/README b/README
index e1cde65..b1e8fb5 100644
--- a/README
+++ b/README
@@ -17,10 +17,10 @@ Example
 
 If you want to give ProGuard a spin right away, try processing the jar itself:
 
-    cd lib
-    java -jar proguard.jar @../examples/proguard.pro
+    cd examples
+    java -jar ../lib/proguard.jar @proguard.pro
 
-The resulting proguard_out.jar contains the same application, but it's much
+The resulting proguard_out.jar contains the same application, but it's a lot
 smaller!
 
 
@@ -51,4 +51,4 @@ Enjoy!
 
 http://proguard.sourceforge.net/
 
-Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
diff --git a/docs/FAQ.html b/docs/FAQ.html
index 16660b8..1947507 100644
--- a/docs/FAQ.html
+++ b/docs/FAQ.html
@@ -17,6 +17,8 @@
 <li><a href="#obfuscation">What is obfuscation?</a>
 <li><a href="#optimization">What kind of optimizations does <b>ProGuard</b>
     support?</a>
+<li><a href="#commercial">Can I use <b>ProGuard</b> to process my commercial
+    application?</a>
 <li><a href="#jdk1.4">Does <b>ProGuard</b> work with JDK1.4? JDK5.0?</a>
 <li><a href="#j2me">Does <b>ProGuard</b> work with J2ME?</a>
 <li><a href="#ant">Does <b>ProGuard</b> have support for Ant?</a>
@@ -63,18 +65,20 @@ Apart from removing unused classes, fields, and methods in the shrinking step,
 <b>ProGuard</b> can also perform optimizations at the bytecode level, inside
 methods:
 <ul>
-<li>Evaluating constant expressions.
-<li>Removing unnecessary computations.
-<li>Removing unnecessary field accesses.
-<li>Removing unnecessary method calls.
-<li>Removing unnecessary branches.
-<li>Removing unnecessary comparisons and instanceof tests.
-<li>Removing write-only fields.
+<li>Evaluate constant expressions.
+<li>Remove unnecessary field accesses.
+<li>Remove unnecessary method calls.
+<li>Remove unnecessary branches.
+<li>Remove unnecessary comparisons and instanceof tests.
+<li>Remove unused code.
+<li>Remove write-only fields.
+<li>Remove unused method parameters.
 <li>Various peephole optimizations like push/pop simplification.
-<li>Making classes and methods final when possible.
-<li>Inlining simple getters and setters when possible.
-<li>Replacing interfaces that have single implementations.
-<li>Optionally removing logging code.
+<li>Make classes static and final when possible.
+<li>Make methods private, static, and final when possible.
+<li>Inline simple getters and setters when possible.
+<li>Replace interfaces that have single implementations.
+<li>Optionally remove logging code.
 </ul>
 The positive effects of these optimizations will depend on your code and on
 the virtual machine on which the code is executed. Simple virtual machines may
@@ -84,6 +88,12 @@ At the very least, your bytecode may become a bit smaller.
 A notable optimization that isn't supported yet is the inlining of constant
 fields that are not marked as final.
 
+<a name="commercial"> </a>
+<h3>Can I use <b>ProGuard</b> to process my commercial application?</h3>
+Yes, you can. <b>ProGuard</b> itself is distributed under the GPL, but this
+doesn't affect the programs that you process. Your code remains yours, and
+its license can remain the same.
+
 <a name="jdk1.4"> </a>
 <h3>Does <b>ProGuard</b> work with JDK1.4? JDK5.0?</h3>
 Yes. Class files compiled with JDK1.4 are targeted at JRE1.2 by default. Class
@@ -170,7 +180,7 @@ Yes. You can specify your own obfuscation dictionary, such as a list of
 reserved key words, identifiers with foreign characters, random source files,
 or a text by Shakespeare. Note that this hardly improves the obfuscation.
 Decent decompilers can automatically replace reserved keywords, and the effect
-can fairly simply be undone by obfuscating again with simpler names.
+can be undone fairly easily, by obfuscating again with simpler names.
 
 <a name="stacktrace"> </a>
 <h3>Can <b>ProGuard</b> reconstruct obfuscated stack traces?</h3>
@@ -184,7 +194,7 @@ Manual</a> for more details.
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/GPL_exception.html b/docs/GPL_exception.html
index 3d136dc..dc43dd1 100644
--- a/docs/GPL_exception.html
+++ b/docs/GPL_exception.html
@@ -7,7 +7,7 @@
 <H1>Special Exception to the GNU General Public License</H1>
 
 <P>
-Copyright © 2002-2004 Eric Lafortune
+Copyright © 2002-2005 Eric Lafortune
 </P>
 
 <P>
@@ -31,13 +31,13 @@ Place, Suite 330, Boston, MA 02111-1307 USA
 
 <P>
 In addition, as a special exception, Eric Lafortune gives permission to link
-the code of this program with Apache Ant, the Sun J2ME Wireless Toolkit, and
-the Eclipse Platform, and distribute linked combinations including the two.
-You must obey the GNU General Public License in all respects for all of the
-code used other than these programs. If you modify this file, you may extend
-this exception to your version of the file, but you are not obligated to do
-so. If you do not wish to do so, delete this exception statement from your
-version.
+the code of this program with the following stand-alone applications: Apache
+Ant, the Sun J2ME Wireless Toolkit, the Eclipse IDE, and the Javaground Tools,
+and distribute linked combinations including the two. You must obey the GNU
+General Public License in all respects for all of the code used other than
+these programs. If you modify this file, you may extend this exception to your
+version of the file, but you are not obligated to do so. If you do not wish to
+do so, delete this exception statement from your version.
 </P>
 
 </BODY>
diff --git a/docs/acknowledgements.html b/docs/acknowledgements.html
index 71bd57c..a65a440 100644
--- a/docs/acknowledgements.html
+++ b/docs/acknowledgements.html
@@ -19,7 +19,7 @@ code in common.
 <p>
 
 Dirk Schnelle has generously contributed and maintained the first versions of
-the Ant task. The implementation has been rewritten for version 3.0, but the
+the Ant task. I have rewritten the implementation for version 3.0, but the
 XML schema is still based on his work.
 <p>
 
@@ -50,7 +50,7 @@ to make programming interesting.
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 
diff --git a/docs/alternatives.html b/docs/alternatives.html
index 6918ecb..8ca2bf9 100644
--- a/docs/alternatives.html
+++ b/docs/alternatives.html
@@ -42,8 +42,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.informatik.uni-oldenburg.de/leute/hoenicke.html">Jochen Hoenicke</a></td>
-<td><a target="other" href="http://jode.sourceforge.net/">Jode</a></td>
+<td><a target="other" rel="nofollow" href="http://www.informatik.uni-oldenburg.de/leute/hoenicke.html">Jochen Hoenicke</a></td>
+<td><a target="other" rel="nofollow" href="http://jode.sourceforge.net/">Jode</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -51,8 +51,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.nq4.de/">NQ4</a></td>
-<td><a target="other" href="http://www.nq4.de/">Joga</a></td>
+<td><a target="other" rel="nofollow" href="http://www.nq4.de/">NQ4</a></td>
+<td><a target="other" rel="nofollow" href="http://www.nq4.de/">Joga</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -60,8 +60,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://sourceforge.net/users/hchacha/">Hidetoshi Ohuchi</a></td>
-<td><a target="other" href="http://jarg.sourceforge.net/">Jarg</a></td>
+<td><a target="other" rel="nofollow" href="http://sourceforge.net/users/hchacha/">Hidetoshi Ohuchi</a></td>
+<td><a target="other" rel="nofollow" href="http://jarg.sourceforge.net/">Jarg</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -69,8 +69,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.geocities.com/CapeCanaveral/Hall/2334/resume.html">Alexander Shvets</a></td>
-<td><a target="other" href="http://www.geocities.com/CapeCanaveral/Hall/2334/Programs/cafebabe.html">CafeBabe</a></td>
+<td><a target="other" rel="nofollow" href="http://www.geocities.com/CapeCanaveral/Hall/2334/resume.html">Alexander Shvets</a></td>
+<td><a target="other" rel="nofollow" href="http://www.geocities.com/CapeCanaveral/Hall/2334/Programs/cafebabe.html">CafeBabe</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -78,8 +78,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.cs.cornell.edu/nystrom/">Nate Nystrom</a></td>
-<td><a target="other" href="http://www.cs.purdue.edu/homes/hosking/bloat/">Bloat</a></td>
+<td><a target="other" rel="nofollow" href="http://www.cs.cornell.edu/nystrom/">Nate Nystrom</a></td>
+<td><a target="other" rel="nofollow" href="http://www.cs.purdue.edu/homes/hosking/bloat/">Bloat</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><br></td>
@@ -87,8 +87,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.cs.purdue.edu/homes/grothoff/">Christian Grothoff</a></td>
-<td><a target="other" href="http://www.ovmj.org/jamit/">Jamit</a></td>
+<td><a target="other" rel="nofollow" href="http://www.cs.purdue.edu/homes/grothoff/">Christian Grothoff</a></td>
+<td><a target="other" rel="nofollow" href="http://www.ovmj.org/jamit/">Jamit</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
@@ -96,8 +96,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.riggshill.com/">RiggsHill Software</a></td>
-<td><a target="other" href="http://genjar.sourceforge.net/">GenJar</a></td>
+<td><a target="other" rel="nofollow" href="http://www.riggshill.com/">RiggsHill Software</a></td>
+<td><a target="other" rel="nofollow" href="http://genjar.sourceforge.net/">GenJar</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
@@ -105,8 +105,17 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.sable.mcgill.ca/">Sable</a></td>
-<td><a target="other" href="http://www.sable.mcgill.ca/soot/">Soot</a></td>
+<td><a target="other" rel="nofollow" href="http://sadun-util.sourceforge.net/">Cristiano Sadun</a></td>
+<td><a target="other" rel="nofollow" href="http://sadun-util.sourceforge.net/pack.html">Pack</a></td>
+<td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
+<td align="center"><br></td>
+<td align="center"><br></td>
+<td>Free (LGPL)</td>
+</tr>
+
+<tr>
+<td><a target="other" rel="nofollow" href="http://www.sable.mcgill.ca/">Sable</a></td>
+<td><a target="other" rel="nofollow" href="http://www.sable.mcgill.ca/soot/">Soot</a></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><br></td>
@@ -114,8 +123,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.utdallas.edu/~gxz014000/">Bajie</a></td>
-<td><a target="other" href="http://www.utdallas.edu/~gxz014000/jcmp/">JCMP</a></td>
+<td><a target="other" rel="nofollow" href="http://www.utdallas.edu/~gxz014000/">Bajie</a></td>
+<td><a target="other" rel="nofollow" href="http://www.utdallas.edu/~gxz014000/jcmp/">JCMP</a></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -123,8 +132,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.retrologic.com/">RetroLogic</a></td>
-<td><a target="other" href="http://www.retrologic.com/">RetroGuard</a></td>
+<td><a target="other" rel="nofollow" href="http://www.retrologic.com/">RetroLogic</a></td>
+<td><a target="other" rel="nofollow" href="http://www.retrologic.com/">RetroGuard</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -132,8 +141,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://sourceforge.net/users/glurk/">Thorsten Heit</a></td>
-<td><a target="other" href="http://sourceforge.net/projects/javaguard/">JavaGuard</a></td>
+<td><a target="other" rel="nofollow" href="http://sourceforge.net/users/glurk/">Thorsten Heit</a></td>
+<td><a target="other" rel="nofollow" href="http://sourceforge.net/projects/javaguard/">JavaGuard</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -141,8 +150,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://mwobfu.sourceforge.net/">Patrick Mueller</a></td>
-<td><a target="other" href="http://mwobfu.sourceforge.net/">Mwobfu</a></td>
+<td><a target="other" rel="nofollow" href="http://mwobfu.sourceforge.net/">Patrick Mueller</a></td>
+<td><a target="other" rel="nofollow" href="http://mwobfu.sourceforge.net/">Mwobfu</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -150,8 +159,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.yworks.com/">yWorks</a></td>
-<td><a target="other" href="http://www.yworks.com/en/products_yguard_about.htm">yGuard</a></td>
+<td><a target="other" rel="nofollow" href="http://www.yworks.com/">yWorks</a></td>
+<td><a target="other" rel="nofollow" href="http://www.yworks.com/en/products_yguard_about.htm">yGuard</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -159,8 +168,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.drjava.de/">Dr. Java</a></td>
-<td><a target="other" href="http://www.drjava.de/obfuscator/">Marvin Obfuscator</a></td>
+<td><a target="other" rel="nofollow" href="http://www.drjava.de/">Dr. Java</a></td>
+<td><a target="other" rel="nofollow" href="http://www.drjava.de/obfuscator/">Marvin Obfuscator</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -168,8 +177,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.alphaworks.ibm.com/">IBM AlphaWorks</a></td>
-<td><a target="other" href="http://www.alphaworks.ibm.com/tech/jax/">JAX</a></td>
+<td><a target="other" rel="nofollow" href="http://www.alphaworks.ibm.com/">IBM AlphaWorks</a></td>
+<td><a target="other" rel="nofollow" href="http://www.alphaworks.ibm.com/tech/jax/">JAX</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -177,8 +186,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.preemptive.com/">PreEmptive</a></td>
-<td><a target="other" href="http://www.preemptive.com/products.html">DashOPro</a></td>
+<td><a target="other" rel="nofollow" href="http://www.preemptive.com/">PreEmptive</a></td>
+<td><a target="other" rel="nofollow" href="http://www.preemptive.com/products.html">DashOPro</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -186,8 +195,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.zelix.com/">Zelix</a></td>
-<td><a target="other" href="http://www.zelix.com/klassmaster/index.html">KlassMaster</a></td>
+<td><a target="other" rel="nofollow" href="http://www.zelix.com/">Zelix</a></td>
+<td><a target="other" rel="nofollow" href="http://www.zelix.com/klassmaster/index.html">KlassMaster</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -195,8 +204,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.s5systems.com/">S5 Systems</a></td>
-<td><a target="other" href="http://www.s5systems.com/jPresto.htm">jPresto</a></td>
+<td><a target="other" rel="nofollow" href="http://www.s5systems.com/">S5 Systems</a></td>
+<td><a target="other" rel="nofollow" href="http://www.s5systems.com/jPresto.htm">jPresto</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -204,8 +213,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.codingart.com/">CodingArt</a></td>
-<td><a target="other" href="http://www.codingart.com/codeshield.html">CodeShield</a></td>
+<td><a target="other" rel="nofollow" href="http://www.codingart.com/">CodingArt</a></td>
+<td><a target="other" rel="nofollow" href="http://www.codingart.com/codeshield.html">CodeShield</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -213,8 +222,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.e-t.com/">Eastridge Technology</a></td>
-<td><a target="other" href="http://www.e-t.com/jshrink.html">Jshrink</a></td>
+<td><a target="other" rel="nofollow" href="http://www.e-t.com/">Eastridge Technology</a></td>
+<td><a target="other" rel="nofollow" href="http://www.e-t.com/jshrink.html">Jshrink</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -222,8 +231,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.helseth.com/">Helseth</a></td>
-<td><a target="other" href="http://www.helseth.com/HJO.htm">JObfuscator</a></td>
+<td><a target="other" rel="nofollow" href="http://www.helseth.com/">Helseth</a></td>
+<td><a target="other" rel="nofollow" href="http://www.helseth.com/HJO.htm">JObfuscator</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -231,8 +240,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.leesw.com/">LeeSoftware</a></td>
-<td><a target="other" href="http://www.leesw.com/">Smokescreen Obfuscator</a></td>
+<td><a target="other" rel="nofollow" href="http://www.leesw.com/">LeeSoftware</a></td>
+<td><a target="other" rel="nofollow" href="http://www.leesw.com/">Smokescreen Obfuscator</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -240,8 +249,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.vegatech.com/">Vega Technologies</a></td>
-<td><a target="other" href="http://www.vegatech.com/jzipper/">JZipper</a></td>
+<td><a target="other" rel="nofollow" href="http://www.vegatech.com/">Vega Technologies</a></td>
+<td><a target="other" rel="nofollow" href="http://www.vegatech.com/jzipper/">JZipper</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -249,8 +258,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.uni-vologda.ac.ru/~c3c/">Sergey Sverdlov</a></td>
-<td><a target="other" href="http://www.uni-vologda.ac.ru/~c3c/jco/">J.Class Optimizer</a></td>
+<td><a target="other" rel="nofollow" href="http://www.uni-vologda.ac.ru/~c3c/">Sergey Sverdlov</a></td>
+<td><a target="other" rel="nofollow" href="http://www.uni-vologda.ac.ru/~c3c/jco/">J.Class Optimizer</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><br></td>
@@ -258,8 +267,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://cs.arizona.edu/">U. of Arizona</a></td>
-<td><a target="other" href="http://sandmark.cs.arizona.edu/">SandMark</a></td>
+<td><a target="other" rel="nofollow" href="http://cs.arizona.edu/">U. of Arizona</a></td>
+<td><a target="other" rel="nofollow" href="http://sandmark.cs.arizona.edu/">SandMark</a></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -267,8 +276,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.force5.com/">Force 5</a></td>
-<td><a target="other" href="http://www.force5.com/">JCloak</a></td>
+<td><a target="other" rel="nofollow" href="http://www.force5.com/">Force 5</a></td>
+<td><a target="other" rel="nofollow" href="http://www.force5.com/">JCloak</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -276,8 +285,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.wingsoft.com/">WingSoft</a></td>
-<td><a target="other" href="http://www.wingsoft.com/wingguard.html">WingGuard</a></td>
+<td><a target="other" rel="nofollow" href="http://www.wingsoft.com/">WingSoft</a></td>
+<td><a target="other" rel="nofollow" href="http://www.wingsoft.com/wingguard.html">WingGuard</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -285,8 +294,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.jammconsulting.com/">JAMM Consulting</a></td>
-<td><a target="other" href="http://www.jammconsulting.com/jamm/servlet/com.jammconsulting.servlet.JAMMServlet?pageId=ObfuscateProPage">ObfuscatePro</a></td>
+<td><a target="other" rel="nofollow" href="http://www.jammconsulting.com/">JAMM Consulting</a></td>
+<td><a target="other" rel="nofollow" href="http://www.jammconsulting.com/jamm/servlet/com.jammconsulting.servlet.JAMMServlet?pageId=ObfuscateProPage">ObfuscatePro</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -294,8 +303,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.2lkit.com/">2LKit</a></td>
-<td><a target="other" href="http://www.2lkit.com/products/2LKitObf/index.htm">2LKit Obfuscator</a></td>
+<td><a target="other" rel="nofollow" href="http://www.2lkit.com/">2LKit</a></td>
+<td><a target="other" rel="nofollow" href="http://www.2lkit.com/products/2LKitObf/index.htm">2LKit Obfuscator</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -303,8 +312,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.duckware.com/">Duckware</a></td>
-<td><a target="other" href="http://www.duckware.com/jobfuscate/">Jobfuscate</a></td>
+<td><a target="other" rel="nofollow" href="http://www.duckware.com/">Duckware</a></td>
+<td><a target="other" rel="nofollow" href="http://www.duckware.com/jobfuscate/">Jobfuscate</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -312,8 +321,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.jproof.com/">JProof</a></td>
-<td><a target="other" href="http://www.jproof.com/">JProof</a></td>
+<td><a target="other" rel="nofollow" href="http://www.jproof.com/">JProof</a></td>
+<td><a target="other" rel="nofollow" href="http://www.jproof.com/">JProof</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -321,8 +330,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.4fang.net/">4Fang</a></td>
-<td><a target="other" href="http://www.4fang.net/jmix/">JMix</a></td>
+<td><a target="other" rel="nofollow" href="http://www.4fang.net/">4Fang</a></td>
+<td><a target="other" rel="nofollow" href="http://www.4fang.net/jmix/">JMix</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -330,8 +339,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.solutia.ro/">GITS</a></td>
-<td><a target="other" href="http://www.solutia.ro/pages/javadc/">Blurfuscator</a></td>
+<td><a target="other" rel="nofollow" href="http://www.solutia.ro/">GITS</a></td>
+<td><a target="other" rel="nofollow" href="http://www.solutia.ro/pages/javadc/">Blurfuscator</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -339,8 +348,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.jdevelop.com/">JDevelop</a></td>
-<td><a target="other" href="http://www.jdevelop.com/best-java-obfuscator.html">JSCO</a></td>
+<td><a target="other" rel="nofollow" href="http://www.jdevelop.com/">JDevelop</a></td>
+<td><a target="other" rel="nofollow" href="http://www.jdevelop.com/best-java-obfuscator.html">JSCO</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -348,8 +357,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://sourceforge.net/projects/flmobf/">Alain Moran</a></td>
-<td><a target="other" href="http://sourceforge.net/projects/flmobf/">flmObf</a></td>
+<td><a target="other" rel="nofollow" href="http://sourceforge.net/projects/flmobf/">Alain Moran</a></td>
+<td><a target="other" rel="nofollow" href="http://sourceforge.net/projects/flmobf/">flmObf</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -357,8 +366,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.chez.com/vasile/">Vasile Calmatui</a></td>
-<td><a target="other" href="http://www.chez.com/vasile/obfu/VasObfuLite.html">VasObfuLite</a></td>
+<td><a target="other" rel="nofollow" href="http://www.chez.com/vasile/">Vasile Calmatui</a></td>
+<td><a target="other" rel="nofollow" href="http://www.chez.com/vasile/obfu/VasObfuLite.html">VasObfuLite</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -366,8 +375,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www-i2.informatik.rwth-aachen.de/~markusj/">Markus Jansen</a></td>
-<td><a target="other" href="http://www-i2.informatik.rwth-aachen.de/~markusj/jopt/">Jopt</a></td>
+<td><a target="other" rel="nofollow" href="http://www-i2.informatik.rwth-aachen.de/~markusj/">Markus Jansen</a></td>
+<td><a target="other" rel="nofollow" href="http://www-i2.informatik.rwth-aachen.de/~markusj/jopt/">Jopt</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -375,8 +384,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.primenet.com/~ej">Eron Jokipii</a></td>
-<td><a target="other" href="http://www.primenet.com/~ej">Jobe</a></td>
+<td><a target="other" rel="nofollow" href="http://www.primenet.com/~ej">Eron Jokipii</a></td>
+<td><a target="other" rel="nofollow" href="http://www.primenet.com/~ej">Jobe</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -384,8 +393,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://jrc.krdl.org.sg/">JRC</a></td>
-<td><a target="other" href="http://jrc.krdl.org.sg/decaf/">DeCaf</a></td>
+<td><a target="other" rel="nofollow" href="http://jrc.krdl.org.sg/">JRC</a></td>
+<td><a target="other" rel="nofollow" href="http://jrc.krdl.org.sg/decaf/">DeCaf</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -393,8 +402,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.plumbdesign.com/">Plumb Design</a></td>
-<td><a target="other" href="http://www.condensity.com/">Condensity</a></td>
+<td><a target="other" rel="nofollow" href="http://www.plumbdesign.com/">Plumb Design</a></td>
+<td><a target="other" rel="nofollow" href="http://www.condensity.com/">Condensity</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -402,8 +411,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.4thpass.com/">4th Pass</a></td>
-<td><a target="other" href="http://www.4thpass.com/">SourceGuard</a></td>
+<td><a target="other" rel="nofollow" href="http://www.4thpass.com/">4th Pass</a></td>
+<td><a target="other" rel="nofollow" href="http://www.4thpass.com/">SourceGuard</a></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -411,8 +420,8 @@ incorrect.
 </tr>
 
 <tr>
-<td><a target="other" href="http://www.sbktech.org/">HashJava</a></td>
-<td><a target="other" href="http://www.sbktech.org/">HashJava</a></td>
+<td><a target="other" rel="nofollow" href="http://www.sbktech.org/">HashJava</a></td>
+<td><a target="other" rel="nofollow" href="http://www.sbktech.org/">HashJava</a></td>
 <td align="center"><br></td>
 <td align="center"><br></td>
 <td align="center"><img src="checkmark.gif" width="11" height="11" alt="x"></td>
@@ -425,7 +434,7 @@ All trademarks are property of their respective holders.
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 
diff --git a/docs/downloads.html b/docs/downloads.html
index c695e33..06c1eea 100644
--- a/docs/downloads.html
+++ b/docs/downloads.html
@@ -34,6 +34,28 @@ updates with sub-minor version numbers. These versions are typically released
 shortly after their parent versions, for applying emergency fixes.
 <p>
 
+<h3>Version 3.3</h3>
+<ul>
+<li>Extended optimizations: making methods private and static when possible,
+    making classes static when possible, removing unused parameters.
+<li>Made file names relative to the configuration files in which they are
+    specified. Added <code>-basedirectory</code> option.
+<li>Added <code>-whyareyoukeeping</code> option to get details on why given
+    classes and class members are being kept.
+<li>Added warnings for misplaced class files.
+<li>Improved printing of notes for Class.forName constructs.
+<li>Implemented '<code>assumenosideeffects</code>' nested element in Ant task.
+<li>Improved processing of annotations.
+<li>Fixed reading and writing of parameter annotations.
+<li>Fixed various optimization bugs.
+<li>Fixed wildcards not matching '-' character.
+<li>Fixed wildcard bug and checkbox bugs in GUI.
+<li>Setting file chooser defaults in GUI.
+<li>Leaving room for growBox in GUI on Mac OS X.
+<li>Properly closing configuration files.
+<li>Updated documentation and examples.
+</ul>
+
 <h3>Version 3.2</h3>
 <ul>
 <li>Fixed JDK5.0 processing bugs.
@@ -58,7 +80,7 @@ shortly after their parent versions, for applying emergency fixes.
 
 <h3>Version 3.0</h3>
 <ul>
-<li>Added bytecode optimization step, inbetween shrinking step and obfuscation
+<li>Added bytecode optimization step, between shrinking step and obfuscation
     step.
 <li>Generalized filtered recursive reading and writing of jars, wars, ears,
     zips, and directories.
@@ -213,7 +235,7 @@ shortly after their parent versions, for applying emergency fixes.
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 
diff --git a/docs/feedback.html b/docs/feedback.html
index 43ae9e9..eddbca6 100644
--- a/docs/feedback.html
+++ b/docs/feedback.html
@@ -17,16 +17,16 @@ problems, bugs, bug fixes, ideas, encouragements, etc. to share, please go
 ahead:
 <p>
 <ul>
-<li>A good place to share your thoughts about <b>ProGuard</b> is the <a
-    href="http://sourceforge.net/forum/forum.php?forum_id=182455"
-    target="other">open discussion forum</a> (at <a
+<li>If you need help with <b>ProGuard</b>, please go to the <a
+    href="http://sourceforge.net/forum/forum.php?forum_id=182456"
+    target="other">help forum</a> (at <a
     href="http://sourceforge.net/projects/proguard/"
     target="other">SourceForge</a>).
     <p>
 
-<li>If you need help, please go to the <a
-    href="http://sourceforge.net/forum/forum.php?forum_id=182456"
-    target="other">help forum</a> (at <a
+<li>A good place to share your thoughts is the <a
+    href="http://sourceforge.net/forum/forum.php?forum_id=182455"
+    target="other">open discussion forum</a> (at <a
     href="http://sourceforge.net/projects/proguard/"
     target="other">SourceForge</a>).
     <p>
@@ -95,10 +95,16 @@ document.write("</a>");
 <p>
 I can't promise a swift answer, or any answer at all, for that matter, but I'd
 love to see your responses.
+<p>
+
+This isn't a typical open source project in the sense that I am not looking
+for code contributions. Developing ProGuard on my own allows me to do things
+my way, without the overhead of project management and the compromises
+associated with larger projects.
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 
diff --git a/docs/license.html b/docs/license.html
index 97d1f78..917d7f6 100644
--- a/docs/license.html
+++ b/docs/license.html
@@ -11,35 +11,35 @@
 <h2>License</h2>
 
 <b>ProGuard</b> is free. I wrote it for the challenge of it. And for eternal
-fame and glory, of course. You can use it for whatever purpose you deem
-useful. This includes processing your applications, commercial or not. Your
-code obviously remains yours after processing.
+fame and glory, of course. You can use it freely for processing your
+applications, commercial or not. Your code obviously remains yours after
+having been processed, and its license can remain the same.
 <p>
 
-<b>ProGuard</b> is copyrighted, but the distribution license provides you with
-some rights for modifying and redistributing its code and its documentation.
-<p>
-<b>ProGuard</b> is distributed under the term of the <a href="GPL.html">GNU
-General Public License</a> (GPL), as published by the <a
-href="http://www.fsf.org/" target="other">Free Software Foundation</a> (FSF).
-In short, this means that you may freely redistribute the program, modified or
-as is, on the condition that you make the complete source code available as
-well. If you develop a program that is linked with <b>ProGuard</b>, the
-program as a whole has to be distributed at no charge under the GPL. I am
-granting a <a href="GPL_exception.html">special exception</a> to the latter
-clause (in wording suggested by the <a
+<b>ProGuard</b> itself is copyrighted, but its distribution license provides
+you with some rights for modifying and redistributing its code and its
+documentation. More specifically, <b>ProGuard</b> is distributed under the
+terms of the <a href="GPL.html">GNU General Public License</a> (GPL), as
+published by the <a href="http://www.fsf.org/" target="other">Free Software
+Foundation</a> (FSF). In short, this means that you may freely redistribute
+the program, modified or as is, on the condition that you make the complete
+source code available as well. If you develop a program that is linked with
+<b>ProGuard</b>, the program as a whole has to be distributed at no charge
+under the GPL. I am granting a <a href="GPL_exception.html">special
+exception</a> to the latter clause (in wording suggested by the <a
 href="http://www.gnu.org/copyleft/gpl-faq.html#GPLIncompatibleLibs"
-target="other">FSF</a>), for combinations with Apache Ant, the Sun J2ME
-Wireless Toolkit, and the Eclipse Platform.
+target="other">FSF</a>), for combinations with the following stand-alone
+applications: Apache Ant, the Sun J2ME Wireless Toolkit, the Eclipse IDE, and
+the Javaground Tools.
 
 <p>
-The user documentation represents an important part of this work. It may only
-be redistributed without changes, along with the unmodified version of the
-code.
+The <b>ProGuard user documentation</b> represents an important part of this
+work. It may only be redistributed without changes, along with the unmodified
+version of the code.
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/main.html b/docs/main.html
index b782bf1..633d2c3 100644
--- a/docs/main.html
+++ b/docs/main.html
@@ -72,7 +72,7 @@ The following sections provide more detailed information:
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/manual/ant.html b/docs/manual/ant.html
index 1043397..676ee64 100644
--- a/docs/manual/ant.html
+++ b/docs/manual/ant.html
@@ -81,9 +81,9 @@ Some minor syntactical changes are required in order to conform with the XML
 standard.
 <p>
 
-Firstly, the <code>#</code> chararacter cannot be used for comments in an XML
+Firstly, the <code>#</code> character cannot be used for comments in an XML
 file. Comments must be enclosed by an opening <code><!--</code> and a
-closing <code>--></code>. All occurrences of the <code>#</code> chararacter
+closing <code>--></code>. All occurrences of the <code>#</code> character
 can be removed.
 <p>
 
@@ -263,6 +263,14 @@ elements:
     all of the specified class members are present (after the shrinking
     step).</dd>
 
+<dt><code><b><whyareyoukeeping</b></code>
+    <a href="#classspecification"><i>class_specification</i></a>
+    <code><b>></b></code>
+    <a href="#classmemberspecification"><i>class_member_specifications</i></a>
+    <code><b></whyareyoukeeping></b></code></dt>
+<dd>Print details on why the given classes and class members are being kept in
+    the shrinking step.</dd>
+
 <dt><code><b><assumenosideeffects</b></code>
     <a href="#classspecification"><i>class_specification</i></a>
     <code><b>></b></code>
@@ -410,7 +418,7 @@ attributes:
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/manual/examples.html b/docs/manual/examples.html
index 647ca03..69c800f 100644
--- a/docs/manual/examples.html
+++ b/docs/manual/examples.html
@@ -342,6 +342,10 @@ ensure that:
 Note the use of <code>-keepclasseswithmembernames</code>. We don't want to
 preserve all classes or all native methods; we just want to keep the relevant
 names from being obfuscated.
+<p>
+ProGuard doesn't have your native code, so it can't automatically preserve the
+classes or class members that are invoked by the native code. These are entry
+points, which you'll have to specify explicitly.
 
 <a name="enumerations"> </a>
 <h3>Processing enumeration classes</h3>
@@ -677,7 +681,7 @@ processing the input jar at all.
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/manual/gui.html b/docs/manual/gui.html
index 7880b6e..ff5e13e 100644
--- a/docs/manual/gui.html
+++ b/docs/manual/gui.html
@@ -343,7 +343,9 @@ Corresponding configuration options:
 <h2>The Information Tab</h2>
 
 The <i>Information</i> tab presents a number of options that affect the
-information that ProGuard returns when processing your code.
+information that ProGuard returns when processing your code. The bottom list
+allows you to query ProGuard about why given classes and class members are
+being kept in the shrinking step.
 <p>
 
 Corresponding configuration options:
@@ -355,6 +357,7 @@ Corresponding configuration options:
 <li>-<a href="usage.html#ignorewarnings">ignorewarnings</a>
 <li>-<a href="usage.html#dontskipnonpubliclibraryclasses">dontskipnonpubliclibraryclasses</a>
 <li>-<a href="usage.html#dontskipnonpubliclibraryclassmembers">dontskipnonpubliclibraryclassmembers</a>
+<li>-<a href="usage.html#whyareyoukeeping">whyareyoukeeping</a>
 </ul>
 <p>
 
@@ -411,7 +414,7 @@ There are two buttons at the bottom:
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/manual/index.html b/docs/manual/index.html
index a4c9ee9..8f8e630 100644
--- a/docs/manual/index.html
+++ b/docs/manual/index.html
@@ -32,7 +32,7 @@
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/manual/introduction.html b/docs/manual/introduction.html
index f8e939e..8855676 100644
--- a/docs/manual/introduction.html
+++ b/docs/manual/introduction.html
@@ -81,7 +81,9 @@ midlets, etc.
 
 <li>In the <b>optimization step</b>, ProGuard further optimizes the code.
     Among other optimizations, classes and methods that are not entry points
-    can be made final, and some methods may be inlined.
+    can be made private, static, or final, unused parameters can be removed,
+    and some methods may be inlined.
+
 <li>In the <b>obfuscation step</b>, ProGuard renames classes and class members
     that are not entry points. In this entire process, keeping the entry
     points ensures that they can still be accessed by their original names.
@@ -109,7 +111,7 @@ accordingly.
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/manual/limitations.html b/docs/manual/limitations.html
index b69544f..3b36cae 100644
--- a/docs/manual/limitations.html
+++ b/docs/manual/limitations.html
@@ -38,17 +38,23 @@ easily avoided or resolved:
     graphical user interface has a checkbox for this setting.
     <p>
 
-<li>For best results, ProGuard's <b>optimization</b> algorithms assume that
-    the processed code never intentionally causes NullPointerExceptions and
-    ArrayIndexOutOfBoundsExceptions to achieve something useful. For instance,
+<li>For best results, ProGuard's optimization algorithms assume that the
+    processed code never <b>intentionally throws NullPointerExceptions</b> or
+    ArrayIndexOutOfBoundsExceptions, or even OutOfMemoryErrors or
+    StackOverflowErrors, in order to achieve something useful. For instance,
     it may remove a method call <code>myObject.myMethod()</code> if that call
     wouldn't have any effect. It ignores that <code>myObject</code> might be
     null, causing a NullPointerException. In some way this is a good thing:
-    optimized code may throw fewer exceptions. Should this entire assumption be
-    false, you'll have to switch off optimization using the
+    optimized code may throw fewer exceptions. Should this entire assumption
+    be false, you'll have to switch off optimization using the
     <code>-dontoptimize</code> option.
     <p>
 
+<li>ProGuard's optimization algorithms also remove all <b>empty busy-waiting
+    loops</b>. You should avoid these, or otherwise, you'll have to switch off
+    optimization using the <code>-dontoptimize</code> option.
+    <p>
+
 <li>If an input jar and a library jar contain classes in the <b>same
     package</b>, the obfuscated output jar may contain class names that
     overlap with class names in the library jar. This is most likely if the
@@ -88,7 +94,7 @@ easily avoided or resolved:
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/manual/refcard.html b/docs/manual/refcard.html
index cf10b47..42594ab 100644
--- a/docs/manual/refcard.html
+++ b/docs/manual/refcard.html
@@ -36,6 +36,12 @@
 </tr>
 
 <tr>
+<td valign="top"><code><b>-basedirectory</b></code> <i>directoryname</i></td>
+
+<td>Specifies the base directory for subsequent relative file names.</td>
+</tr>
+
+<tr>
 <td valign="top"><code><b>-injars</b></code> <i>class_path</i></td>
 <td>Specifies the program jars (or wars, ears, zips, or directories).</td>
 </tr>
@@ -120,6 +126,13 @@
 </tr>
 
 <tr>
+<td valign="top"><code><b>-whyareyoukeeping</b></code>
+    <i>class_specification</i></td>
+<td>Print details on why the given classes and class members are being kept in
+    the shrinking step.</td>
+</tr>
+
+<tr>
 <td valign="top"><code><b>-dontoptimize</b></code></td>
 <td>Don't optimize the input class files.</td>
 </tr>
@@ -298,7 +311,7 @@ Notes:
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/manual/retrace/examples.html b/docs/manual/retrace/examples.html
index 75f7ae4..f5657c5 100644
--- a/docs/manual/retrace/examples.html
+++ b/docs/manual/retrace/examples.html
@@ -328,7 +328,7 @@ Exception in thread "main" java.lang.Error: Random exception
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/manual/retrace/index.html b/docs/manual/retrace/index.html
index d69eaea..6f586ab 100644
--- a/docs/manual/retrace/index.html
+++ b/docs/manual/retrace/index.html
@@ -18,7 +18,7 @@
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/manual/retrace/introduction.html b/docs/manual/retrace/introduction.html
index e90e150..40495fc 100644
--- a/docs/manual/retrace/introduction.html
+++ b/docs/manual/retrace/introduction.html
@@ -58,7 +58,7 @@ original class names and class member names to their obfuscated names.
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/manual/retrace/usage.html b/docs/manual/retrace/usage.html
index 239c39c..55bdd6d 100644
--- a/docs/manual/retrace/usage.html
+++ b/docs/manual/retrace/usage.html
@@ -73,7 +73,7 @@ will be left unchanged.
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/manual/troubleshooting.html b/docs/manual/troubleshooting.html
index b598108..28542c1 100644
--- a/docs/manual/troubleshooting.html
+++ b/docs/manual/troubleshooting.html
@@ -44,7 +44,18 @@ ProGuard may print out some notes and non-fatal warnings:
     switch off these notes by specifying the <code>-dontnote</code>
     option.</dd>
 
-<dt><a name="duplicatezipentry"><b>Warning: can't write resource... Duplicate zip entry</b></a></dt>
+<dt><a name="unexpectedclass"><b>Note: class file ... unexpectedly contains class ...</b></a></dt>
+
+<dd>The given class file contains a definition for the given class, but the
+    directory name of the file doesn't correspond to the package name of the
+    class. ProGuard will accept the class definition, but the current
+    implementation will not write out the processed version. Please make sure
+    your input classes are packaged correctly. Notably, class files that are
+    in the <code>WEB-INF/classes</code> directory in a war should be packaged
+    in a jar and put in the <code>WEB-INF/lib</code> directory. You can switch
+    off these notes by specifying the <code>-dontnote</code> option.</dd>
+
+<dt><a name="duplicatezipentry"><b>Warning: can't write resource ... Duplicate zip entry</b></a></dt>
 
 <dd>Your input jars contain multiple resource files with the same name.
     ProGuard continues copying the resource files as usual, skipping any files
@@ -74,7 +85,10 @@ some more serious warnings:
     <code>java.util.zip.ZipConstants</code>, which is used as an interface
     class in some public classes, even though it is only package visible (in
     this case, the warning could also be ignored, because the class is not a
-    fundamental part of the class hierarchy).
+    fundamental part of the class hierarchNotably,
+    class files that are in the <code>WEB-INF/classes</code> directory in a
+    war should be packaged in a jar and put in the <code>WEB-INF/lib</code>
+    directory.y).
     <p>
     If you're missing a library and you're absolutely sure it isn't used
     anyway, you can try your luck with the <code>-ignorewarnings</code>
@@ -88,6 +102,15 @@ some more serious warnings:
     source file was removed. Try removing all class files, recompiling them,
     zipping them up, and running ProGuard again.
     <p>
+    If the class member that is reported as missing is actually implemented in
+    a non-public library class, you should specify the
+    <code>-dontskipnonpubliclibraryclasses</code> option. A common example is
+    the method <code>setLength(int)</code> in the public class
+    <code>java.lang.StringBuilder</code>. This method is actually defined in
+    the package visible superclass
+    <code>java.lang.AbstractStringBuilder</code>, which ProGuard ignores by
+    default.
+    <p>
     If your program classes reside in the same packages as library classes,
     and refer to their package visible class members, then you should specify
     the <code>-dontskipnonpubliclibraryclassmembers</code> option.</dd>
@@ -161,7 +184,14 @@ might be several reasons:
     tools often let class files with similar lower-case and upper-case names
     overwrite each other. If you really can't switch to a different operating
     system, you could consider using ProGuard's
-    <code>-dontusemixedcaseclassnames</code> option.</dd>
+    <code>-dontusemixedcaseclassnames</code> option.
+    <p>
+    Also, you should make sure your class files are in directories that
+    correspond to their package names. ProGuard will read misplaced class
+    files, but it will currently not write their processed versions. Notably,
+    class files that are in the <code>WEB-INF/classes</code> directory in a
+    war should be packaged in a jar and put in the <code>WEB-INF/lib</code>
+    directory.</dd>
 
 <dt><a name="notkept"><b>Classes or class members not being kept</b></a></dt>
 
@@ -220,6 +250,15 @@ might be several reasons:
     forgotten to preverify your program jar <i>after</i> having processed it
     with ProGuard.</dd>
 
+<dt><a name="failingmidlets"><b>Failing midlets in J2ME</b></a></dt>
+
+<dd>If your midlet simply won't start, you might try using the
+    <code>-dontusemixedcaseclassnames</code> option. Even if it has been
+    properly processed and then preverified on a case-sensitive file system,
+    the device itself might not like the mixed-case class names. Notably, the
+    Nokia N-Gage emulator works fine, but the actual device seems to exhibit
+    this problem.</dd>
+
 <dt><a name="securityexception"><b>SecurityException: SHA1 digest error</b></a></dt>
 
 <dd>You may have forgotten to sign your program jar <i>after</i> having
@@ -236,6 +275,14 @@ might be several reasons:
     <code>proguard/wtk/default.pro</code> that's inside the
     <code>proguard.jar</code>.</dd>
 
+<dt><a name="compilererror"><b>CompilerError: duplicate addition</b></a></dt>
+
+<dd>You are probably compiling or running some code that has been obfuscated
+    with the <code>-overloadaggressively</code> option. This option triggers a
+    bug in <code>sun.tools.java.MethodSet.add</code> in Sun's JDK 1.2.2, which
+    is used for (dynamic) compilation. You should then not use this
+    option.</dd>
+
 <dt><a name="classformaterror"><b>ClassFormatError: repetitive field name/signature</b></a></dt>
 
 <dd>You are probably processing some code that has been obfuscated before with
@@ -257,12 +304,20 @@ might be several reasons:
     please report it, preferably with the simplest example on which you can
     find ProGuard to fail.</dd>
 
+<dt><a name="verifyerror"><b>VerifyError: Unable to pop operand off an empty
+    stack</b></a></dt>
+
+<dd>Verification errors when executing a program are almost certainly the
+    result of a bug in the optimization step of ProGuard. Make sure you are
+    using the latest version. You should be able to work around the problem by
+    using the <code>-dontoptimize</code> option. Please report it, preferably
+    with the simplest example on which you can find ProGuard to fail.</dd>
+
 </dl>
-<p>
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/manual/usage.html b/docs/manual/usage.html
index 6b96def..cfa8ecb 100644
--- a/docs/manual/usage.html
+++ b/docs/manual/usage.html
@@ -71,6 +71,12 @@ The sections below provide more details:
 <dd>Recursively reads configuration options from the given file
     <i>filename</i>.</dd>
 
+<dt><a name="basedirectory"><code><b>-basedirectory</b></code></a>
+    <a href="#filename"><i>directoryname</i></a></dt>
+
+<dd>Specifies the base directory for all subsequent relative file names in
+    these configuration arguments or this configuration file.</dd>
+
 <dt><a name="injars"><code><b>-injars</b></code></a>
     <a href="#classpath"><i>class_path</i></a></dt>
 
@@ -250,6 +256,21 @@ The sections below provide more details:
     href="examples.html#deadcode">list the unused code of an application</a>.
     Only applicable when shrinking.</dd>
 
+<dt><a name="whyareyoukeeping"><code><b>-whyareyoukeeping</b></code></a>
+    <a href="#classspecification"><i>class_specification</i></a></dt>
+
+<dd>Specifies to print details on why the given classes and class members are
+    being kept in the shrinking step. This can be useful if you are wondering
+    why some given element is present in the output. In general, there can be
+    many different reasons. This option prints the shortest chain of methods
+    to a specified seed or entry point, for each specified class and class
+    member. <i>In the current implementation, the shortest chain that is
+    printed out may sometimes contain circular reasonings -- these do not
+    reflect the actual shrinking process.</i> If the <a
+    href="#verbose"><code><b>-verbose</b></code></a> option if specified, the
+    traces include full field and method signatures. Only applicable when
+    shrinking.</dd>
+
 </dl>
 <p>
 
@@ -489,7 +510,7 @@ The sections below provide more details:
 <a name="classpath"> </a>
 <h2>Class Paths</h2>
 
-ProGuard accepts a generalisation of class paths to specify input files and
+ProGuard accepts a generalization of class paths to specify input files and
 output files. A class path consists of entries, separated by the path
 separator (e.g. '<b>:</b>' on Unix, or '<b>;</b>' on Windows platforms). The
 order of the entries determines their priorities, in case of duplicates.
@@ -541,7 +562,13 @@ possibilities.
 <h2>File Names</h2>
 
 ProGuard accepts absolute paths and relative paths for the various file names
-and directory names.
+and directory names. A relative path is interpreted as follows:
+<ul>
+<li>relative to the base directory, if set, or otherwise
+<li>relative to the configuration file in which it is specified, if any, or
+    otherwise
+<li>relative to the working directory.
+</ul>
 <p>
 The names can contain Java system properties delimited by '<b><</b>' and
 '<b>></b>'. The system properties
@@ -549,11 +576,15 @@ are automatically replaced by their respective values.
 <p>
 For example, <code><java.home>/lib/rt.jar</code> will automatically be
 expanded to something like <code>/usr/local/java/jdk/jre/lib/rt.jar</code>.
+Similarly, <code><user.home></code> will be expanded to the user's home
+directory, and <code><user.dir></code> will be expanded to the current
+working directory.
 <p>
-Names with special characters like spaces and parentheses must be quoted
-with single or double quotes. Note that each file name in a list of names has
-to be quoted individually. Also note that the quotes may need to be escaped
-when used on the command line, to avoid them being gobbled by the shell.
+Names with special characters like spaces and parentheses must be quoted with
+single or double quotes. Note that each file name in a list of names has to be
+quoted individually. Also note that the quotes themselves may need to be
+escaped when used on the command line, to avoid them being gobbled by the
+shell.
 <p>
 For example, on the command line, you could use an option like <code>'-injars
 "my program.jar":"/your directory/your program.jar"'</code>.
@@ -842,7 +873,7 @@ files.
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/manual/wtk.html b/docs/manual/wtk.html
index 5c3325f..ca5c36d 100644
--- a/docs/manual/wtk.html
+++ b/docs/manual/wtk.html
@@ -51,7 +51,7 @@ that's inside the <code>proguard.jar</code>.
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/quality.html b/docs/quality.html
index fe8f4df..1214b26 100644
--- a/docs/quality.html
+++ b/docs/quality.html
@@ -30,7 +30,7 @@ full-screen size.
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/results.html b/docs/results.html
index b62a629..d185032 100644
--- a/docs/results.html
+++ b/docs/results.html
@@ -126,7 +126,7 @@ library jars and program jars.
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 
diff --git a/docs/screenshots.html b/docs/screenshots.html
index 61f401b..94cd3ba 100644
--- a/docs/screenshots.html
+++ b/docs/screenshots.html
@@ -49,7 +49,7 @@ You can click on the image to see the full-size version.
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 </body>
diff --git a/docs/testimonials.html b/docs/testimonials.html
index 87a4faa..558ac3c 100644
--- a/docs/testimonials.html
+++ b/docs/testimonials.html
@@ -90,7 +90,7 @@ You could've been rich.
 
 <hr>
 <address>
-Copyright © 2002-2004
+Copyright © 2002-2005
 <a href="http://www.graphics.cornell.edu/~eric/">Eric Lafortune</a>.
 </address>
 
diff --git a/docs/title.html b/docs/title.html
index 09f51c8..6087887 100644
--- a/docs/title.html
+++ b/docs/title.html
@@ -11,7 +11,7 @@
 <table class="title">
 <tr>
 <th class="title"><h1><img src="title.gif" width="154" height="29" alt="ProGuard"></h1></th>
-<td class="title" width="100">Version 3.2</td>
+<td class="title" width="100">Version 3.3.2</td>
 </tr>
 </table>
 
diff --git a/examples/ant/proguard.xml b/examples/ant/proguard.xml
index 8cd44f0..6ec0ca9 100644
--- a/examples/ant/proguard.xml
+++ b/examples/ant/proguard.xml
@@ -17,7 +17,7 @@
     <!-- Specify the input jars, output jars, and library jars. -->
 
     <injar  file="lib/proguard.jar" />
-    <outjar file="proguard_out.jar" />
+    <outjar file="examples/ant/proguard_out.jar" />
 
     <libraryjar file="${java.home}/lib/rt.jar" />
     <libraryjar file="/usr/local/java/ant1.6.2/lib/ant.jar" />
diff --git a/examples/proguard.pro b/examples/proguard.pro
index 1a4a7b7..925e669 100644
--- a/examples/proguard.pro
+++ b/examples/proguard.pro
@@ -8,7 +8,7 @@
 # Specify the input jars, output jars, and library jars.
 # We'll filter out the Ant and WTK classes, keeping everything else.
 
--injars  proguard.jar(!proguard/ant/**,!proguard/wtk/**)
+-injars  ../lib/proguard.jar(!proguard/ant/**,!proguard/wtk/**)
 -outjars proguard_out.jar
 
 -libraryjars <java.home>/lib/rt.jar
diff --git a/examples/proguardall.pro b/examples/proguardall.pro
index b0e14e1..346edb9 100644
--- a/examples/proguardall.pro
+++ b/examples/proguardall.pro
@@ -11,7 +11,7 @@
 # We'll read all jars from the lib directory, process them, and write the
 # processed jars to a new out directory.
 
--injars  lib
+-injars  ../lib
 -outjars out
 
 # You may have to adapt the paths below.
diff --git a/examples/proguardgui.pro b/examples/proguardgui.pro
index 1dca7bd..dfbf66a 100644
--- a/examples/proguardgui.pro
+++ b/examples/proguardgui.pro
@@ -6,10 +6,12 @@
 #
 
 # Specify the input jars, output jars, and library jars.
-# We'll filter out the Ant and WTK classes, keeping everything else.
+# The input jars will be merged in a single output jar.
+# We'll filter out the Ant and WTK classes.
 
--injars  proguard.jar(!proguard/ant/**,!proguard/wtk/**)
--injars  proguardgui.jar
+-injars  ../lib/proguardgui.jar
+-injars  ../lib/proguard.jar(!META-INF/MANIFEST.MF,
+                             !proguard/ant/**,!proguard/wtk/**)
 -outjars proguardgui_out.jar
 
 -libraryjars <java.home>/lib/rt.jar
diff --git a/examples/retrace.pro b/examples/retrace.pro
index b9aa0f6..8942756 100644
--- a/examples/retrace.pro
+++ b/examples/retrace.pro
@@ -6,10 +6,12 @@
 #
 
 # Specify the input jars, output jars, and library jars.
-# We'll filter out the Ant and WTK classes, keeping everything else.
+# The input jars will be merged in a single output jar.
+# We'll filter out the Ant and WTK classes.
 
--injars  proguard.jar(!proguard/ant/**,!proguard/wtk/**)
--injars  retrace.jar
+-injars  ../lib/retrace.jar
+-injars  ../lib/proguard.jar(!META-INF/MANIFEST.MF,
+                             !proguard/ant/**,!proguard/wtk/**)
 -outjars retrace_out.jar
 
 -libraryjars <java.home>/lib/rt.jar
diff --git a/lib/proguard.jar b/lib/proguard.jar
new file mode 100644
index 0000000..e48c6f7
Binary files /dev/null and b/lib/proguard.jar differ
diff --git a/lib/proguardgui.jar b/lib/proguardgui.jar
new file mode 100644
index 0000000..b77d428
Binary files /dev/null and b/lib/proguardgui.jar differ
diff --git a/lib/retrace.jar b/lib/retrace.jar
new file mode 100644
index 0000000..1dca452
Binary files /dev/null and b/lib/retrace.jar differ
diff --git a/src/proguard/ArgumentWordReader.java b/src/proguard/ArgumentWordReader.java
index 7494205..b0e4fef 100644
--- a/src/proguard/ArgumentWordReader.java
+++ b/src/proguard/ArgumentWordReader.java
@@ -1,8 +1,8 @@
-/* $Id: ArgumentWordReader.java,v 1.11 2004/08/15 12:39:30 eric Exp $
+/* $Id: ArgumentWordReader.java,v 1.14 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -35,11 +35,23 @@ public class ArgumentWordReader extends WordReader
     private int      index = 0;
 
 
+//    /**
+//     * Creates a new ArgumentWordReader for the given arguments.
+//     */
+//    public ArgumentWordReader(String[] arguments)
+//    {
+//        this(arguments, null);
+//    }
+//
+//
     /**
-     * Creates a new ArgumentWordReader for the given arguments.
+     * Creates a new ArgumentWordReader for the given arguments, with the
+     * given base directory.
      */
-    public ArgumentWordReader(String[] arguments)
+    public ArgumentWordReader(String[] arguments, File baseDir)
     {
+        super(baseDir);
+
         this.arguments = arguments;
     }
 
@@ -65,18 +77,33 @@ public class ArgumentWordReader extends WordReader
      * the argument list.
      */
     public static void main(String[] args) {
+
         try
         {
-            WordReader reader = new ArgumentWordReader(args);
-            while (true)
+            WordReader reader = new ArgumentWordReader(args, null);
+
+            try
             {
-                String word = reader.nextWord();
-                if (word == null)
-                    System.exit(-1);
+                while (true)
+                {
+                    String word = reader.nextWord();
+                    if (word == null)
+                        System.exit(-1);
 
-                System.err.println("["+word+"]");
+                    System.err.println("["+word+"]");
+                }
+            }
+            catch (Exception ex)
+            {
+                ex.printStackTrace();
             }
-        } catch (Exception ex) {
+            finally
+            {
+                reader.close();
+            }
+        }
+        catch (IOException ex)
+        {
             ex.printStackTrace();
         }
     }
diff --git a/src/proguard/ClassMemberSpecification.java b/src/proguard/ClassMemberSpecification.java
index 45cfab1..389721f 100644
--- a/src/proguard/ClassMemberSpecification.java
+++ b/src/proguard/ClassMemberSpecification.java
@@ -1,8 +1,8 @@
-/* $Id: ClassMemberSpecification.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: ClassMemberSpecification.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/ClassPath.java b/src/proguard/ClassPath.java
index 4df62c6..70dac03 100644
--- a/src/proguard/ClassPath.java
+++ b/src/proguard/ClassPath.java
@@ -1,8 +1,8 @@
-/* $Id: ClassPath.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: ClassPath.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/ClassPathEntry.java b/src/proguard/ClassPathEntry.java
index 808efbb..f526891 100644
--- a/src/proguard/ClassPathEntry.java
+++ b/src/proguard/ClassPathEntry.java
@@ -1,8 +1,8 @@
-/* $Id: ClassPathEntry.java,v 1.8 2004/08/15 12:39:30 eric Exp $
+/* $Id: ClassPathEntry.java,v 1.10 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -20,6 +20,8 @@
  */
 package proguard;
 
+import java.io.*;
+
 
 /**
  * This class represents an entry from a class path: a jar, a war, a zip, an
@@ -31,7 +33,7 @@ package proguard;
  */
 public class ClassPathEntry
 {
-    private String  name;
+    private File    file;
     private boolean output;
     private String  filter;
     private String  jarFilter;
@@ -43,21 +45,38 @@ public class ClassPathEntry
     /**
      * Creates a new ClassPathEntry with the given name and type.
      */
-    public ClassPathEntry(String name, boolean isOutput)
+    public ClassPathEntry(File file, boolean isOutput)
     {
-        this.name   = name;
+        this.file   = file;
         this.output = isOutput;
     }
 
 
+    /**
+     * Returns the path name of the entry.
+     */
     public String getName()
     {
-        return name;
+        try
+        {
+            return file.getCanonicalPath();
+        }
+        catch (IOException ex)
+        {
+            return file.getPath();
+        }
+    }
+
+
+    public File getFile()
+    {
+        return file;
     }
 
-    public void setName(String name)
+
+    public void setFile(File file)
     {
-        this.name = name;
+        this.file = file;
     }
 
 
@@ -130,7 +149,7 @@ public class ClassPathEntry
 
     public String toString()
     {
-        String string = name;
+        String string = getName();
 
         if (filter    != null ||
             jarFilter != null ||
diff --git a/src/proguard/ClassSpecification.java b/src/proguard/ClassSpecification.java
index faeb157..28eb248 100644
--- a/src/proguard/ClassSpecification.java
+++ b/src/proguard/ClassSpecification.java
@@ -1,8 +1,8 @@
-/* $Id: ClassSpecification.java,v 1.3 2004/08/28 17:03:30 eric Exp $
+/* $Id: ClassSpecification.java,v 1.4 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/Configuration.java b/src/proguard/Configuration.java
index 7ebe8f1..109ab21 100644
--- a/src/proguard/Configuration.java
+++ b/src/proguard/Configuration.java
@@ -1,8 +1,8 @@
-/* $Id: Configuration.java,v 1.14 2004/11/20 15:41:24 eric Exp $
+/* $Id: Configuration.java,v 1.17 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -21,6 +21,7 @@
 package proguard;
 
 import java.util.*;
+import java.io.File;
 
 
 /**
@@ -76,10 +77,10 @@ public class Configuration
     public List      keepNames;
 
     /**
-     * An optional output file name for listing the kept seeds.
-     * An empty string means the standard output.
+     * An optional output file for listing the kept seeds.
+     * An empty file name means the standard output.
      */
-    public String    printSeeds;
+    public File      printSeeds;
 
     ///////////////////////////////////////////////////////////////////////////
     // Shrinking options.
@@ -91,10 +92,16 @@ public class Configuration
     public boolean   shrink                      = true;
 
     /**
-     * An optional output file name for listing the unused classes and class
-     * members. An empty string means the standard output.
+     * An optional output file for listing the unused classes and class
+     * members. An empty file name means the standard output.
      */
-    public String    printUsage;
+    public File      printUsage;
+
+    /**
+     * A list of {@link ClassSpecification} instances, for which an explanation
+     * is to be printed, why they are kept in the shrinking step.
+     */
+    public List      whyAreYouKeeping;
 
     ///////////////////////////////////////////////////////////////////////////
     // Optimization options.
@@ -126,20 +133,20 @@ public class Configuration
     public boolean   obfuscate                   = true;
 
     /**
-     * An optional output file name for listing the obfuscation mapping.
-     * An empty string means the standard output.
+     * An optional output file for listing the obfuscation mapping.
+     * An empty file name means the standard output.
      */
-    public String    printMapping;
+    public File      printMapping;
 
     /**
-     * An optional input file name for reading an obfuscation mapping.
+     * An optional input file for reading an obfuscation mapping.
      */
-    public String    applyMapping;
+    public File      applyMapping;
 
     /**
      * An optional name of a file containing obfuscated class member names.
      */
-    public String    obfuscationDictionary;
+    public File      obfuscationDictionary;
 
     /**
      * Specifies whether to apply aggressive name overloading on class members.
@@ -195,8 +202,8 @@ public class Configuration
     public boolean   ignoreWarnings              = false;
 
     /**
-     * An optional output file name for printing out the processed code in a
-     * more or less readable form. An empty string means the standard output.
+     * An optional output file for printing out the processed code in a more
+     * or less readable form. An empty file name means the standard output.
      */
-    public String    dump;
+    public File      dump;
 }
diff --git a/src/proguard/ConfigurationConstants.java b/src/proguard/ConfigurationConstants.java
index 6b13a26..3c6a6ca 100644
--- a/src/proguard/ConfigurationConstants.java
+++ b/src/proguard/ConfigurationConstants.java
@@ -1,4 +1,4 @@
-/* $Id: ConfigurationConstants.java,v 1.10 2004/11/20 15:41:24 eric Exp $
+/* $Id: ConfigurationConstants.java,v 1.12 2005/06/11 14:50:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
@@ -30,6 +30,7 @@ class ConfigurationConstants
     public static final String OPTION_PREFIX                                     = "-";
     public static final String AT_DIRECTIVE                                      = "@";
     public static final String INCLUDE_DIRECTIVE                                 = "-include";
+    public static final String BASE_DIRECTORY_DIRECTIVE                          = "-basedirectory";
 
     public static final String INJARS_OPTION                                     = "-injars";
     public static final String OUTJARS_OPTION                                    = "-outjars";
@@ -46,6 +47,7 @@ class ConfigurationConstants
 
     public static final String DONT_SHRINK_OPTION                                = "-dontshrink";
     public static final String PRINT_USAGE_OPTION                                = "-printusage";
+    public static final String WHY_ARE_YOU_KEEPING_OPTION                        = "-whyareyoukeeping";
 
     public static final String DONT_OPTIMIZE_OPTION                              = "-dontoptimize";
     public static final String ASSUME_NO_SIDE_EFFECTS_OPTION                     = "-assumenosideeffects";
diff --git a/src/proguard/ConfigurationParser.java b/src/proguard/ConfigurationParser.java
index 63700e7..523b40a 100644
--- a/src/proguard/ConfigurationParser.java
+++ b/src/proguard/ConfigurationParser.java
@@ -1,8 +1,8 @@
-/* $Id: ConfigurationParser.java,v 1.19 2004/12/18 20:22:13 eric Exp $
+/* $Id: ConfigurationParser.java,v 1.24 2005/06/11 14:50:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -20,13 +20,13 @@
  */
 package proguard;
 
-import proguard.classfile.*;
-import proguard.classfile.util.*;
-import proguard.util.*;
+import proguard.classfile.ClassConstants;
+import proguard.classfile.util.ClassUtil;
+import proguard.util.ListUtil;
 
 import java.io.*;
-import java.net.URL;
 import java.util.*;
+import java.net.URL;
 
 
 /**
@@ -47,17 +47,30 @@ public class ConfigurationParser
      */
     public ConfigurationParser(String[] args) throws IOException
     {
-        reader = new ArgumentWordReader(args);
+        this(args, null);
+    }
+
+
+    /**
+     * Creates a new ConfigurationParser for the given String arguments,
+     * with the given base directory.
+     */
+    public ConfigurationParser(String[] args,
+                               File     baseDir) throws IOException
+    {
+        reader = new ArgumentWordReader(args, baseDir);
+
         readNextWord();
     }
 
 
     /**
-     * Creates a new ConfigurationParser for the given file name.
+     * Creates a new ConfigurationParser for the given file.
      */
-    public ConfigurationParser(String fileName) throws IOException
+    public ConfigurationParser(File file) throws IOException
     {
-        reader = new FileWordReader(fileName);
+        reader = new FileWordReader(file);
+
         readNextWord();
     }
 
@@ -68,6 +81,7 @@ public class ConfigurationParser
     public ConfigurationParser(URL url) throws IOException
     {
         reader = new FileWordReader(url);
+
         readNextWord();
     }
 
@@ -79,7 +93,8 @@ public class ConfigurationParser
      *                        a syntax error.
      * @throws IOException if an IO error occurs while reading a configuration.
      */
-    public void parse(Configuration configuration) throws ParseException, IOException
+    public void parse(Configuration configuration)
+    throws ParseException, IOException
     {
         while (nextWord != null)
         {
@@ -88,6 +103,7 @@ public class ConfigurationParser
             // First include directives.
             if      (ConfigurationConstants.AT_DIRECTIVE                                     .startsWith(nextWord) ||
                      ConfigurationConstants.INCLUDE_DIRECTIVE                                .startsWith(nextWord)) parseIncludeArgument();
+            else if (ConfigurationConstants.BASE_DIRECTORY_DIRECTIVE                         .startsWith(nextWord)) parseBaseDirectoryArgument();
 
             // Then configuration options with or without arguments.
             else if (ConfigurationConstants.INJARS_OPTION                                    .startsWith(nextWord)) configuration.programJars                      = parseClassPathArgument(configuration.programJars, false);
@@ -103,19 +119,20 @@ public class ConfigurationParser
             else if (ConfigurationConstants.KEEP_NAMES_OPTION                                .startsWith(nextWord)) configuration.keepNames                        = parseClassSpecificationArguments(configuration.keepNames, true,  false);
             else if (ConfigurationConstants.KEEP_CLASS_MEMBER_NAMES_OPTION                   .startsWith(nextWord)) configuration.keepNames                        = parseClassSpecificationArguments(configuration.keepNames, false, false);
             else if (ConfigurationConstants.KEEP_CLASSES_WITH_MEMBER_NAMES_OPTION            .startsWith(nextWord)) configuration.keepNames                        = parseClassSpecificationArguments(configuration.keepNames, false, true);
-            else if (ConfigurationConstants.PRINT_SEEDS_OPTION                               .startsWith(nextWord)) configuration.printSeeds                       = parseOptionalArgument();
+            else if (ConfigurationConstants.PRINT_SEEDS_OPTION                               .startsWith(nextWord)) configuration.printSeeds                       = parseOptionalFile();
 
             else if (ConfigurationConstants.DONT_SHRINK_OPTION                               .startsWith(nextWord)) configuration.shrink                           = parseNoArgument(false);
-            else if (ConfigurationConstants.PRINT_USAGE_OPTION                               .startsWith(nextWord)) configuration.printUsage                       = parseOptionalArgument();
+            else if (ConfigurationConstants.PRINT_USAGE_OPTION                               .startsWith(nextWord)) configuration.printUsage                       = parseOptionalFile();
+            else if (ConfigurationConstants.WHY_ARE_YOU_KEEPING_OPTION                       .startsWith(nextWord)) configuration.whyAreYouKeeping                 = parseClassSpecificationArguments(configuration.whyAreYouKeeping, true, false);
 
             else if (ConfigurationConstants.DONT_OPTIMIZE_OPTION                             .startsWith(nextWord)) configuration.optimize                         = parseNoArgument(false);
             else if (ConfigurationConstants.ASSUME_NO_SIDE_EFFECTS_OPTION                    .startsWith(nextWord)) configuration.assumeNoSideEffects              = parseClassSpecificationArguments(configuration.assumeNoSideEffects, false, false);
             else if (ConfigurationConstants.ALLOW_ACCESS_MODIFICATION_OPTION                 .startsWith(nextWord)) configuration.allowAccessModification          = parseNoArgument(true);
 
             else if (ConfigurationConstants.DONT_OBFUSCATE_OPTION                            .startsWith(nextWord)) configuration.obfuscate                        = parseNoArgument(false);
-            else if (ConfigurationConstants.PRINT_MAPPING_OPTION                             .startsWith(nextWord)) configuration.printMapping                     = parseOptionalArgument();
-            else if (ConfigurationConstants.APPLY_MAPPING_OPTION                             .startsWith(nextWord)) configuration.applyMapping                     = parseOptionalArgument();
-            else if (ConfigurationConstants.OBFUSCATION_DICTIONARY_OPTION                    .startsWith(nextWord)) configuration.obfuscationDictionary            = parseObfuscationDictionaryArgument();
+            else if (ConfigurationConstants.PRINT_MAPPING_OPTION                             .startsWith(nextWord)) configuration.printMapping                     = parseOptionalFile();
+            else if (ConfigurationConstants.APPLY_MAPPING_OPTION                             .startsWith(nextWord)) configuration.applyMapping                     = parseFile();
+            else if (ConfigurationConstants.OBFUSCATION_DICTIONARY_OPTION                    .startsWith(nextWord)) configuration.obfuscationDictionary            = parseFile();
             else if (ConfigurationConstants.OVERLOAD_AGGRESSIVELY_OPTION                     .startsWith(nextWord)) configuration.overloadAggressively             = parseNoArgument(true);
             else if (ConfigurationConstants.DEFAULT_PACKAGE_OPTION                           .startsWith(nextWord)) configuration.defaultPackage                   = ClassUtil.internalClassName(parseOptionalArgument());
             else if (ConfigurationConstants.DONT_USE_MIXED_CASE_CLASS_NAMES_OPTION           .startsWith(nextWord)) configuration.useMixedCaseClassNames           = parseNoArgument(false);
@@ -126,7 +143,7 @@ public class ConfigurationParser
             else if (ConfigurationConstants.DONT_NOTE_OPTION                                 .startsWith(nextWord)) configuration.note                             = parseNoArgument(false);
             else if (ConfigurationConstants.DONT_WARN_OPTION                                 .startsWith(nextWord)) configuration.warn                             = parseNoArgument(false);
             else if (ConfigurationConstants.IGNORE_WARNINGS_OPTION                           .startsWith(nextWord)) configuration.ignoreWarnings                   = parseNoArgument(true);
-            else if (ConfigurationConstants.DUMP_OPTION                                      .startsWith(nextWord)) configuration.dump                             = parseOptionalArgument();
+            else if (ConfigurationConstants.DUMP_OPTION                                      .startsWith(nextWord)) configuration.dump                             = parseOptionalFile();
             else
             {
                 throw new ParseException("Unknown configuration " + reader.locationDescription());
@@ -135,13 +152,37 @@ public class ConfigurationParser
     }
 
 
-    private void parseIncludeArgument()
-    throws ParseException, IOException
+
+    /**
+     * Closes the configuration.
+     * @throws IOException if an IO error occurs while closing the configuration.
+     */
+    public void close() throws IOException
+    {
+        if (reader != null)
+        {
+            reader.close();
+        }
+    }
+
+
+    private void parseIncludeArgument() throws ParseException, IOException
     {
         // Read the configuation file name.
         readNextWord("configuration file name");
 
-        reader.includeWordReader(new FileWordReader(replaceSystemProperties(nextWord)));
+        reader.includeWordReader(new FileWordReader(file(nextWord)));
+
+        readNextWord();
+    }
+
+
+    private void parseBaseDirectoryArgument() throws ParseException, IOException
+    {
+        // Read the base directory name.
+        readNextWord("base directory name");
+
+        reader.setBaseDir(file(nextWord));
 
         readNextWord();
     }
@@ -163,8 +204,7 @@ public class ConfigurationParser
             readNextWord("jar or directory name");
 
             // Create a new class path entry.
-            ClassPathEntry entry = new ClassPathEntry(replaceSystemProperties(nextWord),
-                                                      isOutput);
+            ClassPathEntry entry = new ClassPathEntry(file(nextWord), isOutput);
 
             // Read the opening parenthesis or the separator, if any.
             readNextWord();
@@ -286,28 +326,50 @@ public class ConfigurationParser
     }
 
 
-    private String parseObfuscationDictionaryArgument()
+    private File parseFile()
     throws ParseException, IOException
     {
-        // Read the obfsucation dictionary name.
-        readNextWord("obfuscation dictionary name");
+        // Read the obligatory file name.
+        readNextWord("file name");
 
-        String obfuscationDictionary = replaceSystemProperties(nextWord);
+        // Make sure the file is properly resolved.
+        File file = file(nextWord);
 
         readNextWord();
 
-        return obfuscationDictionary;
+        return file;
     }
 
 
-    private String parseOptionalArgument()
-    throws IOException
+    private File parseOptionalFile()
+    throws ParseException, IOException
     {
+        // Read the optional file name.
         readNextWord();
 
         // Didn't the user specify a file name?
         if (configurationEnd())
         {
+            return new File("");
+        }
+
+        // Make sure the file is properly resolved.
+        File file = file(nextWord);
+
+        readNextWord();
+
+        return file;
+    }
+
+
+    private String parseOptionalArgument() throws IOException
+    {
+        // Read the optional argument.
+        readNextWord();
+
+        // Didn't the user specify an argument?
+        if (configurationEnd())
+        {
             return "";
         }
 
@@ -319,8 +381,7 @@ public class ConfigurationParser
     }
 
 
-    private boolean parseNoArgument(boolean value)
-    throws IOException
+    private boolean parseNoArgument(boolean value) throws IOException
     {
         readNextWord();
 
@@ -463,7 +524,8 @@ public class ConfigurationParser
 
 
     private boolean parseClassMemberSpecificationArguments(String             externalClassName,
-                                                           ClassSpecification classSpecification) throws ParseException, IOException
+                                                           ClassSpecification classSpecification)
+    throws ParseException, IOException
     {
         // Parse the class member access modifiers, if any.
         int requiredSetMemberAccessFlags   = 0;
@@ -746,11 +808,37 @@ public class ConfigurationParser
 
 
     /**
+     * Creates a properly resolved File, based on the given word.
+     */
+    private File file(String word) throws ParseException
+    {
+        String fileName = replaceSystemProperties(word);
+        File   file     = new File(fileName);
+
+        // Try to get an absolute file.
+        if (!file.isAbsolute())
+        {
+            file = new File(reader.getBaseDir(), fileName);
+        }
+
+        // Try to get a canonical representation.
+        try
+        {
+            file = file.getCanonicalFile();
+        }
+        catch (IOException ex)
+        {
+        }
+
+        return file;
+    }
+
+
+    /**
      * Replaces any system properties in the given word by their values
      * (e.g. the substring "<java.home>" is replaced by its value).
      */
-    private String replaceSystemProperties(String word)
-    throws ParseException
+    private String replaceSystemProperties(String word) throws ParseException
     {
         int fromIndex = 0;
         while (true)
@@ -805,8 +893,7 @@ public class ConfigurationParser
     /**
      * Reads the next word of the configuration in the 'nextWord' field.
      */
-    private void readNextWord()
-    throws IOException
+    private void readNextWord() throws IOException
     {
         nextWord = reader.nextWord();
     }
@@ -904,14 +991,26 @@ public class ConfigurationParser
     /**
      * A main method for testing configuration parsing.
      */
-    public static void main(String[] args) {
+    public static void main(String[] args)
+    {
         try
         {
             ConfigurationParser parser = new ConfigurationParser(args);
 
-            parser.parse(new Configuration());
+            try
+            {
+                parser.parse(new Configuration());
+            }
+            catch (ParseException ex)
+            {
+                ex.printStackTrace();
+            }
+            finally
+            {
+                parser.close();
+            }
         }
-        catch (Exception ex)
+        catch (IOException ex)
         {
             ex.printStackTrace();
         }
diff --git a/src/proguard/ConfigurationWriter.java b/src/proguard/ConfigurationWriter.java
index 2c3a447..f3f581c 100644
--- a/src/proguard/ConfigurationWriter.java
+++ b/src/proguard/ConfigurationWriter.java
@@ -1,8 +1,8 @@
-/* $Id: ConfigurationWriter.java,v 1.13 2004/11/20 15:41:24 eric Exp $
+/* $Id: ConfigurationWriter.java,v 1.17 2005/06/25 22:09:48 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -49,6 +49,13 @@ public class ConfigurationWriter
         ConfigurationConstants.KEEP_CLASSES_WITH_MEMBERS_OPTION
     };
 
+    private static final String[] WHY_ARE_YOU_KEEPING_OPTIONS = new String[]
+    {
+        ConfigurationConstants.WHY_ARE_YOU_KEEPING_OPTION,
+        ConfigurationConstants.WHY_ARE_YOU_KEEPING_OPTION,
+        ConfigurationConstants.WHY_ARE_YOU_KEEPING_OPTION
+    };
+
     private static final String[] ASSUME_NO_SIDE_EFFECT_OPTIONS = new String[]
     {
         ConfigurationConstants.ASSUME_NO_SIDE_EFFECTS_OPTION,
@@ -58,14 +65,17 @@ public class ConfigurationWriter
 
 
     private PrintWriter writer;
+    private File        baseDir;
 
 
     /**
      * Creates a new ConfigurationWriter for the given file name.
      */
-    public ConfigurationWriter(String configurationFile) throws IOException
+    public ConfigurationWriter(File configurationFile) throws IOException
     {
         this(new PrintWriter(new FileWriter(configurationFile)));
+
+        baseDir = configurationFile.getParentFile();
     }
 
 
@@ -143,6 +153,9 @@ public class ConfigurationWriter
         writeOption(ConfigurationConstants.PRINT_SEEDS_OPTION,                                configuration.printSeeds);
         writer.println();
 
+        // Write the "why are you keeping" options.
+        writeOptions(WHY_ARE_YOU_KEEPING_OPTIONS, configuration.whyAreYouKeeping);
+
         // Write the keep options.
         writeOptions(KEEP_OPTIONS, configuration.keep);
 
@@ -167,7 +180,7 @@ public class ConfigurationWriter
                      outputEntryOptionName :
                      inputEntryOptionName;
 
-                writer.print(optionName + " " + quotedString(entry.getName()));
+                writer.print(optionName + " " + relativeFileName(entry.getFile()));
 
                 // Append the filters, if any.
                 boolean filtered = false;
@@ -230,6 +243,22 @@ public class ConfigurationWriter
     }
 
 
+    private void writeOption(String optionName, File file)
+    {
+        if (file != null)
+        {
+            if (file.getPath().length() > 0)
+            {
+                writer.println(optionName + " " + relativeFileName(file));
+            }
+            else
+            {
+                writer.println(optionName);
+            }
+        }
+    }
+
+
     private void writeOptions(String[] optionNames,
                               List     classSpecifications)
     {
@@ -237,8 +266,7 @@ public class ConfigurationWriter
         {
             for (int index = 0; index < classSpecifications.size(); index++)
             {
-                writeOption(optionNames,
-                                              (ClassSpecification)classSpecifications.get(index));
+                writeOption(optionNames, (ClassSpecification)classSpecifications.get(index));
             }
         }
     }
@@ -391,12 +419,43 @@ public class ConfigurationWriter
     }
 
 
+    /**
+     * Returns a relative file name of the given file, if possible.
+     * The file name is also quoted, if necessary.
+     */
+    private String relativeFileName(File file)
+    {
+        String fileName = file.getAbsolutePath();
+
+        // See if we can convert the file name into a relative file name.
+        if (baseDir != null)
+        {
+            String baseDirName = baseDir.getAbsolutePath() + File.separator;
+            if (fileName.startsWith(baseDirName))
+            {
+                fileName = fileName.substring(baseDirName.length());
+            }
+        }
+
+        return quotedString(fileName);
+    }
+
+
+    /**
+     * Returns a quoted version of the given string, if necessary.
+     */
     private String quotedString(String string)
     {
-        return
-            string.length()     == 0 ||
-            string.indexOf(' ') >= 0  ? ("'" + string + "'") :
-                                        (      string      );
+        return string.length()     == 0 ||
+               string.indexOf(' ') >= 0 ||
+               string.indexOf('@') >= 0 ||
+               string.indexOf('{') >= 0 ||
+               string.indexOf('}') >= 0 ||
+               string.indexOf('(') >= 0 ||
+               string.indexOf(')') >= 0 ||
+               string.indexOf(':') >= 0 ||
+               string.indexOf(';') >= 0  ? ("'" + string + "'") :
+                                           (      string      );
     }
 
 
@@ -406,7 +465,7 @@ public class ConfigurationWriter
     public static void main(String[] args) {
         try
         {
-            ConfigurationWriter writer = new ConfigurationWriter(args[0]);
+            ConfigurationWriter writer = new ConfigurationWriter(new File(args[0]));
 
             writer.write(new Configuration());
         }
diff --git a/src/proguard/DataEntryReaderFactory.java b/src/proguard/DataEntryReaderFactory.java
index e4258d4..03e7a7f 100644
--- a/src/proguard/DataEntryReaderFactory.java
+++ b/src/proguard/DataEntryReaderFactory.java
@@ -1,8 +1,8 @@
-/* $Id: DataEntryReaderFactory.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: DataEntryReaderFactory.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/DataEntryWriterFactory.java b/src/proguard/DataEntryWriterFactory.java
index 318afe7..2f5a5dd 100644
--- a/src/proguard/DataEntryWriterFactory.java
+++ b/src/proguard/DataEntryWriterFactory.java
@@ -1,8 +1,8 @@
-/* $Id: DataEntryWriterFactory.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: DataEntryWriterFactory.java,v 1.4 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -84,14 +84,14 @@ public class DataEntryWriterFactory
                             isWar ? "ear" :
                             isZip ? "zip" :
                                     "directory") +
-                           " [" + classPathEntry.getName() + "]" +
+                           " [" + entryName + "]" +
                            (filter    != null ||
                             jarFilter != null ||
                             warFilter != null ||
                             earFilter != null ||
                             zipFilter != null ? " (filtered)" : ""));
 
-        DataEntryWriter writer = new DirectoryWriter(new File(entryName),
+        DataEntryWriter writer = new DirectoryWriter(classPathEntry.getFile(),
                                                      isJar ||
                                                      isWar ||
                                                      isEar ||
diff --git a/src/proguard/FileWordReader.java b/src/proguard/FileWordReader.java
index 6e2a5c6..082b8cf 100644
--- a/src/proguard/FileWordReader.java
+++ b/src/proguard/FileWordReader.java
@@ -1,8 +1,8 @@
-/* $Id: FileWordReader.java,v 1.9 2004/08/15 12:39:30 eric Exp $
+/* $Id: FileWordReader.java,v 1.12 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -31,19 +31,21 @@ import java.net.URL;
  */
 public class FileWordReader extends WordReader
 {
-    private String           fileName;
+    private String           name;
     private LineNumberReader reader;
 
 
     /**
-     * Creates a new FileWordReader for the given file name.
+     * Creates a new FileWordReader for the given file.
      */
-    public FileWordReader(String fileName) throws IOException
+    public FileWordReader(File file) throws IOException
     {
-        this.fileName = fileName;
-        this.reader   = new LineNumberReader(
-                        new BufferedReader(
-                        new FileReader(fileName)));
+        super(file.getParentFile());
+
+        this.name   = file.getPath();
+        this.reader = new LineNumberReader(
+                      new BufferedReader(
+                      new FileReader(file)));
     }
 
 
@@ -52,23 +54,12 @@ public class FileWordReader extends WordReader
      */
     public FileWordReader(URL url) throws IOException
     {
-        this.fileName = url.getPath();
-        this.reader   = new LineNumberReader(
-                        new BufferedReader(
-                        new InputStreamReader(
-                        url.openStream())));
-    }
-
+        super(null);
 
-    /**
-     * Closes the FileWordReader.
-     */
-    public void close() throws IOException
-    {
-        if (reader != null)
-        {
-            reader.close();
-        }
+        this.name    = url.toString();
+        this.reader  = new LineNumberReader(
+                       new BufferedReader(
+                       new InputStreamReader(url.openStream())));
     }
 
 
@@ -82,6 +73,17 @@ public class FileWordReader extends WordReader
 
     protected String lineLocationDescription()
     {
-        return "line " + reader.getLineNumber() + " of file '" + fileName + "'";
+        return "line " + reader.getLineNumber() + " of file '" + name + "'";
+    }
+
+
+    public void close() throws IOException
+    {
+        super.close();
+
+        if (reader != null)
+        {
+            reader.close();
+        }
     }
 }
diff --git a/src/proguard/GPL.java b/src/proguard/GPL.java
new file mode 100644
index 0000000..007a42a
--- /dev/null
+++ b/src/proguard/GPL.java
@@ -0,0 +1,184 @@
+/* $Id: GPL.java,v 1.3 2005/06/25 22:04:40 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * This class checks and prints out information about the GPL.
+ *
+ * @author Eric Lafortune
+ */
+public class GPL
+{
+    /**
+     * Prints out a note about the GPL if ProGuard is linked against unknown
+     * code.
+     */
+    public static void check()
+    {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        new Exception().printStackTrace(new PrintStream(out));
+        LineNumberReader reader = new LineNumberReader(
+                                  new InputStreamReader(
+                                  new ByteArrayInputStream(out.toByteArray())));
+
+        Set unknownPackageNames = unknownPackageNames(reader);
+
+        if (unknownPackageNames.size() > 0)
+        {
+            String uniquePackageNames = uniquePackageNames(unknownPackageNames);
+
+            System.out.println("ProGuard is released under the GNU General Public License. The authors of all");
+            System.out.println("programs or plugins that link to it ("+uniquePackageNames+"...) therefore");
+            System.out.println("must ensure that these programs carry the GNU General Public License as well.");
+        }
+    }
+
+
+    /**
+     * Returns a set of package names from the given stack trace.
+     */
+    private static Set unknownPackageNames(LineNumberReader reader)
+    {
+        Set packageNames = new HashSet();
+
+        try
+        {
+            while (true)
+            {
+                String line = reader.readLine();
+                if (line == null)
+                {
+                    break;
+                }
+
+                line = line.trim();
+                if (line.startsWith("at "))
+                {
+                    line = line.substring(2).trim();
+                    line = trimSuffix(line, '(');
+                    line = trimSuffix(line, '.');
+                    line = trimSuffix(line, '.');
+
+                    if (line.length() > 0 && !isKnown(line))
+                    {
+                        packageNames.add(line);
+                    }
+                }
+            }
+        }
+        catch (IOException ex)
+        {
+        }
+
+        return packageNames;
+    }
+
+
+    /**
+     * Returns a comma-separated list of package names from the set, excluding
+     * any subpackages of packages in the set.
+     */
+    private static String uniquePackageNames(Set packageNames)
+    {
+        StringBuffer buffer = new StringBuffer();
+
+        Iterator iterator = packageNames.iterator();
+        while (iterator.hasNext())
+        {
+            String packageName = (String)iterator.next();
+            if (!containsPrefix(packageNames, packageName))
+            {
+                buffer.append(packageName).append(", ");
+            }
+        }
+
+        return buffer.toString();
+    }
+
+
+    /**
+     * Returns a given string without the suffix, as defined by the given
+     * separator.
+     */
+    private static String trimSuffix(String string, char separator)
+    {
+        int index = string.lastIndexOf(separator);
+        return index < 0 ? "" : string.substring(0, index);
+    }
+
+
+    /**
+     * Returns whether the given set contains a prefix of the given name.
+     */
+    private static boolean containsPrefix(Set set, String name)
+    {
+        int index = 0;
+
+        while (!set.contains(name.substring(0, index)))
+        {
+            index = name.indexOf('.', index + 1);
+            if (index < 0)
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Returns whether the given package name is has been granted an exception
+     * against the GPL linking clause, by the copyright holder of ProGuard.
+     * This method is not legally binding, but of course the actual license is.
+     * Please contact the copyright holder if you would like an exception for
+     * your code as well.
+     */
+    private static boolean isKnown(String packageName)
+    {
+        return packageName.startsWith("java")                 ||
+               packageName.startsWith("proguard")             ||
+               packageName.startsWith("org.apache.tools.ant") ||
+               packageName.startsWith("org.eclipse")          ||
+               packageName.startsWith("com.sun.kvem")         ||
+               packageName.startsWith("jg.j2me.builder");
+    }
+
+
+    public static void main(String[] args)
+    {
+        LineNumberReader reader = new LineNumberReader(
+                                  new InputStreamReader(System.in));
+
+        Set unknownPackageNames = unknownPackageNames(reader);
+
+        if (unknownPackageNames.size() > 0)
+        {
+            String uniquePackageNames = uniquePackageNames(unknownPackageNames);
+
+            System.out.println(uniquePackageNames);
+        }
+    }
+}
diff --git a/src/proguard/ParseException.java b/src/proguard/ParseException.java
index 82e61a3..e64fc9c 100644
--- a/src/proguard/ParseException.java
+++ b/src/proguard/ParseException.java
@@ -1,8 +1,8 @@
-/* $Id: ParseException.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: ParseException.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/ProGuard.java b/src/proguard/ProGuard.java
index 33d76b3..5fec9d9 100644
--- a/src/proguard/ProGuard.java
+++ b/src/proguard/ProGuard.java
@@ -1,14 +1,15 @@
-/* $Id: ProGuard.java,v 1.84 2004/12/11 16:35:23 eric Exp $
+/* $Id: ProGuard.java,v 1.97 2005/06/26 16:20:23 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
  * Software Foundation; either version 2 of the License, 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
@@ -29,11 +30,13 @@ import proguard.classfile.visitor.*;
 import proguard.io.*;
 import proguard.obfuscate.*;
 import proguard.optimize.*;
-import proguard.optimize.evaluation.*;
+import proguard.optimize.evaluation.PartialEvaluator;
 import proguard.optimize.peephole.*;
 import proguard.shrink.*;
+import proguard.util.*;
 
 import java.io.*;
+import java.util.*;
 
 
 /**
@@ -43,7 +46,7 @@ import java.io.*;
  */
 public class ProGuard
 {
-    public static final String VERSION = "ProGuard, version 3.2";
+    public static final String VERSION = "ProGuard, version 3.3.2";
 
     private Configuration configuration;
     private ClassPool     programClassPool = new ClassPool();
@@ -67,6 +70,8 @@ public class ProGuard
     {
         System.out.println(VERSION);
 
+        GPL.check();
+
         readInput();
 
         if (configuration.shrink   ||
@@ -93,7 +98,9 @@ public class ProGuard
             // Shrink again, if we may.
             if (configuration.shrink)
             {
-                configuration.printUsage = null;
+                // Don't print any usage this time around.
+                configuration.printUsage       = null;
+                configuration.whyAreYouKeeping = null;
 
                 shrink();
             }
@@ -185,6 +192,7 @@ public class ProGuard
             new ClassFileReader(isLibrary,
                                 configuration.skipNonPublicLibraryClasses,
                                 configuration.skipNonPublicLibraryClassMembers,
+                                configuration.note,
             new ClassPoolFiller(classPool, configuration.note)));
     }
 
@@ -241,7 +249,7 @@ public class ProGuard
 
             // Create the data entry pump.
             DirectoryPump directoryPump =
-                new DirectoryPump(new File(classPathEntry.getName()));
+                new DirectoryPump(classPathEntry.getFile());
 
             // Pump the data entries into the reader.
             directoryPump.pumpDataEntries(reader);
@@ -258,6 +266,13 @@ public class ProGuard
      */
     private void initialize() throws IOException
     {
+        if (configuration.verbose)
+        {
+            System.out.println("Initializing...");
+        }
+
+        int originalLibraryClassPoolSize = libraryClassPool.size();
+
         // Initialize the class hierarchy for program class files.
         ClassFileHierarchyInitializer classFileHierarchyInitializer =
             new ClassFileHierarchyInitializer(programClassPool,
@@ -266,7 +281,7 @@ public class ProGuard
 
         programClassPool.classFilesAccept(classFileHierarchyInitializer);
 
-        // Initialize the rest of the class hierarchy.
+        // Initialize the class hierarchy for library class files.
         ClassFileHierarchyInitializer classFileHierarchyInitializer2 =
             new ClassFileHierarchyInitializer(programClassPool,
                                               libraryClassPool,
@@ -274,16 +289,48 @@ public class ProGuard
 
         libraryClassPool.classFilesAccept(classFileHierarchyInitializer2);
 
-        // Initialize the other class references.
+        // Initialize the Class.forName and .class references.
+        ClassFileClassForNameReferenceInitializer classFileClassForNameReferenceInitializer =
+            new ClassFileClassForNameReferenceInitializer(programClassPool,
+                                                          libraryClassPool,
+                                                          configuration.note,
+                                                          createNoteExceptionMatcher(configuration.keep));
+
+        programClassPool.classFilesAccept(
+            new AllMethodVisitor(
+            new AllAttrInfoVisitor(
+            new AllInstructionVisitor(classFileClassForNameReferenceInitializer))));
+
+        // Initialize the class references from program class members and attributes.
         ClassFileReferenceInitializer classFileReferenceInitializer =
             new ClassFileReferenceInitializer(programClassPool,
                                               libraryClassPool,
-                                              configuration.warn,
-                                              configuration.note);
+                                              configuration.warn);
 
         programClassPool.classFilesAccept(classFileReferenceInitializer);
 
-        int noteCount = classFileReferenceInitializer.getNoteCount();
+        // Reinitialize the library class pool with only those library classes
+        // whose hierarchies are referenced by the program classes.
+        ClassPool newLibraryClassPool = new ClassPool();
+        programClassPool.classFilesAccept(
+            new AllCpInfoVisitor(
+            new ReferencedClassFileVisitor(
+            new LibraryClassFileFilter(
+            new ClassFileHierarchyTraveler(true, true, true, false,
+            new LibraryClassFileFilter(
+            new ClassPoolFiller(newLibraryClassPool, false)))))));
+
+        libraryClassPool = newLibraryClassPool;
+
+        // Initialize the class references from library class members.
+        ClassFileReferenceInitializer classFileReferenceInitializer2 =
+            new ClassFileReferenceInitializer(programClassPool,
+                                              libraryClassPool,
+                                              false);
+
+        libraryClassPool.classFilesAccept(classFileReferenceInitializer2);
+
+        int noteCount = classFileClassForNameReferenceInitializer.getNoteCount();
         if (noteCount > 0)
         {
             System.err.println("Note: there were " + noteCount +
@@ -322,29 +369,51 @@ public class ProGuard
         // Discard unused library classes.
         if (configuration.verbose)
         {
-                    System.out.println("Removing unused library classes...");
-                    System.out.println("    Original number of library classes: " + libraryClassPool.size());
+            System.out.println("Removing unused library classes...");
+            System.out.println("  Original number of library classes: " + originalLibraryClassPoolSize);
+            System.out.println("  Final number of library classes:    " + libraryClassPool.size());
         }
+    }
 
-        // Reinitialize the library class pool with only those library classes
-        // whose hierarchies are referenced by the program classes.
-        ClassPool newLibraryClassPool = new ClassPool();
-        programClassPool.classFilesAccept(
-            new AllCpInfoVisitor(
-            new ReferencedClassFileVisitor(
-            new LibraryClassFileFilter(
-            new ClassFileHierarchyTraveler(true, true, true, false,
-            new LibraryClassFileFilter(
-            new ClassPoolFiller(newLibraryClassPool, false)))))));
-
-        libraryClassPool = newLibraryClassPool;
 
-        if (configuration.verbose)
+    /**
+     * Extracts a list of exceptions for which not to print notes, from the
+     * keep configuration.
+     */
+    private ClassNameListMatcher createNoteExceptionMatcher(List noteExceptions)
+    {
+        if (noteExceptions != null)
         {
-            System.out.println("    Final number of library classes:    " + libraryClassPool.size());
+            List noteExceptionNames = new ArrayList(noteExceptions.size());
+            for (int index = 0; index < noteExceptions.size(); index++)
+            {
+                ClassSpecification classSpecification = (ClassSpecification)noteExceptions.get(index);
+                if (classSpecification.markClassFiles)
+                {
+                    // If the class itself is being kept, it's ok.
+                    String className = classSpecification.className;
+                    if (className != null)
+                    {
+                        noteExceptionNames.add(className);
+                    }
+
+                    // If all of its extensions are being kept, it's ok too.
+                    String extendsClassName = classSpecification.extendsClassName;
+                    if (extendsClassName != null)
+                    {
+                        noteExceptionNames.add(extendsClassName);
+                    }
+                }
+            }
+
+            if (noteExceptionNames.size() > 0)
+            {
+                return new ClassNameListMatcher(noteExceptionNames);
+            }
         }
-    }
 
+        return null;
+    }
 
     /**
      * Prints out classes and class members that are used as seeds in the
@@ -363,7 +432,7 @@ public class ProGuard
             throw new IOException("You have to specify '-keep' options for the shrinking step.");
         }
 
-        PrintStream ps = configuration.printSeeds.length() > 0 ?
+        PrintStream ps = isFile(configuration.printSeeds) ?
             new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.printSeeds))) :
             System.out;
 
@@ -402,13 +471,17 @@ public class ProGuard
             throw new IOException("You have to specify '-keep' options for the shrinking step.");
         }
 
+        int originalProgramClassPoolSize = programClassPool.size();
+
         // Clean up any old visitor info.
-        ClassFileCleaner classFileCleaner = new ClassFileCleaner();
-        programClassPool.classFilesAccept(classFileCleaner);
-        libraryClassPool.classFilesAccept(classFileCleaner);
+        programClassPool.classFilesAccept(new ClassFileCleaner());
+        libraryClassPool.classFilesAccept(new ClassFileCleaner());
 
         // Create a visitor for marking the seeds.
-        UsageMarker usageMarker = new UsageMarker();
+        UsageMarker usageMarker = configuration.whyAreYouKeeping == null ?
+            new UsageMarker() :
+            new ShortestUsageMarker();
+
         ClassPoolVisitor classPoolvisitor =
             ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep,
                                                                     usageMarker,
@@ -418,27 +491,52 @@ public class ProGuard
         libraryClassPool.accept(classPoolvisitor);
 
         // Mark interfaces that have to be kept.
-        programClassPool.classFilesAccept(new InterfaceUsageMarker());
+        programClassPool.classFilesAccept(new InterfaceUsageMarker(usageMarker));
 
         // Mark the inner class information that has to be kept.
-        programClassPool.classFilesAccept(new InnerUsageMarker());
+        programClassPool.classFilesAccept(new InnerUsageMarker(usageMarker));
+
+        if (configuration.whyAreYouKeeping != null)
+        {
+            if (configuration.verbose)
+            {
+                System.out.println("Explaining why classes and class members are being kept...");
+            }
+
+            System.out.println();
+
+            // Create a visitor for explaining classes and class members.
+            ShortestUsagePrinter shortestUsagePrinter =
+                new ShortestUsagePrinter((ShortestUsageMarker)usageMarker,
+                                         configuration.verbose);
+
+            ClassPoolVisitor whyClassPoolvisitor =
+                ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.whyAreYouKeeping,
+                                                                        shortestUsagePrinter,
+                                                                        shortestUsagePrinter);
+
+            // Mark the seeds.
+            programClassPool.accept(whyClassPoolvisitor);
+            libraryClassPool.accept(whyClassPoolvisitor);
+        }
 
         if (configuration.printUsage != null)
         {
             if (configuration.verbose)
             {
                 System.out.println("Printing usage" +
-                                   (configuration.printUsage.length() > 0 ?
-                                       " to [" + configuration.printUsage + "]" :
+                                   (isFile(configuration.printUsage) ?
+                                       " to [" + configuration.printUsage.getAbsolutePath() + "]" :
                                        "..."));
             }
 
-            PrintStream ps = configuration.printUsage.length() > 0 ?
+            PrintStream ps = isFile(configuration.printUsage) ?
                 new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.printUsage))) :
                 System.out;
 
             // Print out items that will be removed.
-            programClassPool.classFilesAcceptAlphabetically(new UsagePrinter(true, ps));
+            programClassPool.classFilesAcceptAlphabetically(
+                new UsagePrinter(usageMarker, true, ps));
 
             if (ps != System.out)
             {
@@ -447,25 +545,21 @@ public class ProGuard
         }
 
         // Discard unused program classes.
-        if (configuration.verbose)
-        {
-            System.out.println("Removing unused program classes and class elements...");
-            System.out.println("    Original number of program classes: " + programClassPool.size());
-        }
-
         ClassPool newProgramClassPool = new ClassPool();
         programClassPool.classFilesAccept(
-            new UsedClassFileFilter(
+            new UsedClassFileFilter(usageMarker,
             new MultiClassFileVisitor(
             new ClassFileVisitor[] {
-                new ClassFileShrinker(1024),
+                new ClassFileShrinker(usageMarker, 1024),
                 new ClassPoolFiller(newProgramClassPool, false)
             })));
         programClassPool = newProgramClassPool;
 
         if (configuration.verbose)
         {
-            System.out.println("    Final number of program classes:    " + programClassPool.size());
+            System.out.println("Removing unused program classes and class elements...");
+            System.out.println("  Original number of program classes: " + originalProgramClassPoolSize);
+            System.out.println("  Final number of program classes:    " + programClassPool.size());
         }
 
         // Check if we have at least some output class files.
@@ -487,12 +581,18 @@ public class ProGuard
         }
 
         // Clean up any old visitor info.
-        ClassFileCleaner classFileCleaner = new ClassFileCleaner();
-        programClassPool.classFilesAccept(classFileCleaner);
-        libraryClassPool.classFilesAccept(classFileCleaner);
+        programClassPool.classFilesAccept(new ClassFileCleaner());
+        libraryClassPool.classFilesAccept(new ClassFileCleaner());
+
+        // Link all methods that should get the same optimization info.
+        programClassPool.classFilesAccept(new BottomClassFileFilter(
+                                          new MethodInfoLinker()));
 
         // Check if we have at least some keep commands.
-        if (configuration.keep == null)
+        if (configuration.keep         == null &&
+            configuration.keepNames    == null &&
+            configuration.applyMapping == null &&
+            configuration.printMapping == null)
         {
             throw new IOException("You have to specify '-keep' options for the optimization step.");
         }
@@ -500,23 +600,59 @@ public class ProGuard
         // Create a visitor for marking the seeds.
         KeepMarker keepMarker = new KeepMarker();
         ClassPoolVisitor classPoolvisitor =
-            ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep,
-                                                                    keepMarker,
-                                                                    keepMarker);
+            new MultiClassPoolVisitor(new ClassPoolVisitor[]
+            {
+                ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep,
+                                                                        keepMarker,
+                                                                        keepMarker),
+                ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keepNames,
+                                                                        keepMarker,
+                                                                        keepMarker)
+            });
 
         // Mark the seeds.
         programClassPool.accept(classPoolvisitor);
         libraryClassPool.accept(classPoolvisitor);
 
+        // Attach some optimization info to all methods, so it can be filled
+        // out later.
+        programClassPool.classFilesAccept(new AllMethodVisitor(
+                                          new MethodOptimizationInfoSetter()));
+        libraryClassPool.classFilesAccept(new AllMethodVisitor(
+                                          new MethodOptimizationInfoSetter()));
+
+        // Mark all interfaces that have single implementations.
+        programClassPool.classFilesAccept(new SingleImplementationMarker(configuration.allowAccessModification));
+
         // Make class files and methods final, as far as possible.
         programClassPool.classFilesAccept(new ClassFileFinalizer());
 
-        // Mark all fields that are write-only.
-        programClassPool.classFilesAccept(
-            new AllMethodVisitor(
-            new AllAttrInfoVisitor(
-            new AllInstructionVisitor(
-            new WriteOnlyFieldMarker()))));
+        // Mark all fields that are write-only, and mark the used local variables.
+        programClassPool.classFilesAccept(new AllMethodVisitor(
+                                          new AllAttrInfoVisitor(
+                                          new AllInstructionVisitor(
+                                          new MultiInstructionVisitor(
+                                          new InstructionVisitor[]
+                                          {
+                                              new WriteOnlyFieldMarker(),
+                                              new VariableUsageMarker(),
+                                          })))));
+
+        // Mark all methods that can not be made private.
+        programClassPool.classFilesAccept(new NonPrivateMethodMarker());
+        libraryClassPool.classFilesAccept(new NonPrivateMethodMarker());
+
+        // Make all non-private and unmarked methods in final classes private.
+        programClassPool.classFilesAccept(new ClassFileAccessFilter(ClassConstants.INTERNAL_ACC_FINAL, 0,
+                                          new AllMethodVisitor(
+                                          new MemberInfoAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE,
+                                          new MethodPrivatizer()))));
+
+        // Mark all used parameters, including the 'this' parameters.
+        programClassPool.classFilesAccept(new AllMethodVisitor(
+                                          new ParameterUsageMarker()));
+        libraryClassPool.classFilesAccept(new AllMethodVisitor(
+                                          new ParameterUsageMarker()));
 
         if (configuration.assumeNoSideEffects != null)
         {
@@ -535,21 +671,25 @@ public class ProGuard
         // Mark all methods that have side effects.
         programClassPool.accept(new SideEffectMethodMarker());
 
-        // Mark all interfaces that have single implementations.
-        programClassPool.classFilesAccept(new SingleImplementationMarker(configuration.allowAccessModification));
+        // Perform partial evaluation.
+        programClassPool.classFilesAccept(new AllMethodVisitor(
+                                          new PartialEvaluator()));
 
         // Inline interfaces with single implementations.
-        // First update the references to classes and class members.
-        // Then update the class member descriptors.
-        programClassPool.classFilesAccept(new AllMethodVisitor(
-                                          new AllAttrInfoVisitor(
-                                          new SingleImplementationInliner())));
-        programClassPool.classFilesAccept(new AllMemberInfoVisitor(
-                                          new SingleImplementationInliner()));
+        programClassPool.classFilesAccept(new SingleImplementationInliner());
 
-        // Perform partial evaluation.
+        // Restore the interface references from these single implementations.
+        programClassPool.classFilesAccept(new SingleImplementationFixer());
+
+        // Shrink the method parameters and make methods static.
         programClassPool.classFilesAccept(new AllMethodVisitor(
-                                          new PartialEvaluator()));
+                                          new ParameterShrinker(1024, 64)));
+
+        // Fix all references to class files.
+        programClassPool.classFilesAccept(new ClassFileReferenceFixer());
+
+        // Fix all references to class members.
+        programClassPool.classFilesAccept(new MemberReferenceFixer(1024));
 
         // Create a branch target marker and a code attribute editor that can
         // be reused for all code attributes.
@@ -564,6 +704,7 @@ public class ProGuard
         // - Replace store/load instruction pairs by dup/store instructions.
         // - Replace branches to return instructions by return instructions.
         // - Remove nop instructions.
+        // - Fix invocations of methods that have become private, static,...
         // - Inline simple getters and setters.
         // Finally apply all changes to the code.
         programClassPool.classFilesAccept(
@@ -583,6 +724,7 @@ public class ProGuard
                     new StoreLoadReplacer(branchTargetFinder, codeAttrInfoEditor),
                     new GotoReturnReplacer(codeAttrInfoEditor),
                     new NopRemover(codeAttrInfoEditor),
+                    new MethodInvocationFixer(codeAttrInfoEditor),
                     new GetterSetterInliner(codeAttrInfoEditor, configuration.allowAccessModification),
                 })),
                 codeAttrInfoEditor
@@ -601,20 +743,21 @@ public class ProGuard
         }
 
         // Check if we have at least some keep commands.
-        if (configuration.keep      == null &&
-            configuration.keepNames == null)
+        if (configuration.keep         == null &&
+            configuration.keepNames    == null &&
+            configuration.applyMapping == null &&
+            configuration.printMapping == null)
         {
             throw new IOException("You have to specify '-keep' options for the obfuscation step.");
         }
 
         // Clean up any old visitor info.
-        ClassFileCleaner classFileCleaner = new ClassFileCleaner();
-        programClassPool.classFilesAccept(classFileCleaner);
-        libraryClassPool.classFilesAccept(classFileCleaner);
+        programClassPool.classFilesAccept(new ClassFileCleaner());
+        libraryClassPool.classFilesAccept(new ClassFileCleaner());
 
-        // Link all class members that should get the same names.
+        // Link all methods that should get the same names.
         programClassPool.classFilesAccept(new BottomClassFileFilter(
-                                          new MemberInfoLinker()));
+                                          new MethodInfoLinker()));
 
         // Create a visitor for marking the seeds.
         NameMarker nameMarker = new NameMarker();
@@ -633,12 +776,17 @@ public class ProGuard
         programClassPool.accept(classPoolvisitor);
         libraryClassPool.accept(classPoolvisitor);
 
-        // Apply the mapping, if one has been specified.
+        // All library classes and library class members keep their names.
+        libraryClassPool.classFilesAccept(nameMarker);
+        libraryClassPool.classFilesAccept(new AllMemberInfoVisitor(nameMarker));
+
+        // Apply the mapping, if one has been specified. The mapping can
+        // override the names of library classes and of library class members.
         if (configuration.applyMapping != null)
         {
             if (configuration.verbose)
             {
-                System.out.println("Applying mapping [" + configuration.applyMapping + "]");
+                System.out.println("Applying mapping [" + configuration.applyMapping.getAbsolutePath() + "]");
             }
 
             MappingReader    reader = new MappingReader(configuration.applyMapping);
@@ -680,10 +828,92 @@ public class ProGuard
                                                                   configuration.defaultPackage,
                                                                   configuration.useMixedCaseClassNames));
 
-        // Come up with new names for all class members.
-        programClassPool.classFilesAccept(new BottomClassFileFilter(
-                                          new MemberInfoObfuscator(configuration.overloadAggressively,
-                                                                   configuration.obfuscationDictionary)));
+        NameFactory nameFactory = new SimpleNameFactory();
+
+        if (configuration.obfuscationDictionary != null)
+        {
+            nameFactory = new DictionaryNameFactory(configuration.obfuscationDictionary, nameFactory);
+        }
+
+        Map descriptorMap = new HashMap();
+
+        // Come up with new names for all non-private class members.
+        programClassPool.classFilesAccept(
+            new BottomClassFileFilter(
+            new MultiClassFileVisitor(new ClassFileVisitor[]
+            {
+                // Collect all non-private member names in this name space.
+                new ClassFileHierarchyTraveler(true, true, true, false,
+                new AllMemberInfoVisitor(
+                new MemberInfoAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE,
+                new MemberInfoNameCollector(configuration.overloadAggressively,
+                                            descriptorMap)))),
+
+                // Assign new names to all non-private members in this name space.
+                new ClassFileHierarchyTraveler(true, true, true, false,
+                new AllMemberInfoVisitor(
+                new MemberInfoAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE,
+                new MemberInfoObfuscator(configuration.overloadAggressively,
+                                         nameFactory,
+                                         descriptorMap)))),
+
+                // Clear the collected names.
+                new MapCleaner(descriptorMap)
+            })));
+
+        // Come up with new names for all private class members.
+        programClassPool.classFilesAccept(
+            new MultiClassFileVisitor(new ClassFileVisitor[]
+            {
+                // Collect all member names in this class.
+                new AllMemberInfoVisitor(
+                new MemberInfoNameCollector(configuration.overloadAggressively,
+                                            descriptorMap)),
+
+                // Collect all non-private member names higher up the hierarchy.
+                new ClassFileHierarchyTraveler(false, true, true, false,
+                new AllMemberInfoVisitor(
+                new MemberInfoAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE,
+                new MemberInfoNameCollector(configuration.overloadAggressively,
+                                            descriptorMap)))),
+
+                // Assign new names to all private members in this class.
+                new AllMemberInfoVisitor(
+                new MemberInfoAccessFilter(ClassConstants.INTERNAL_ACC_PRIVATE, 0,
+                new MemberInfoObfuscator(configuration.overloadAggressively,
+                                         nameFactory,
+                                         descriptorMap))),
+
+                // Clear the collected names.
+                new MapCleaner(descriptorMap)
+            }));
+
+        // Some class members may have ended up with conflicting names.
+        // Collect all special member names.
+        programClassPool.classFilesAccept(
+            new AllMemberInfoVisitor(
+            new MemberInfoSpecialNameFilter(
+            new MemberInfoNameCollector(configuration.overloadAggressively,
+                                        descriptorMap))));
+        libraryClassPool.classFilesAccept(
+            new AllMemberInfoVisitor(
+            new MemberInfoSpecialNameFilter(
+            new MemberInfoNameCollector(configuration.overloadAggressively,
+                                        descriptorMap))));
+
+        // Replace the conflicting member names with special, globally unique names.
+        programClassPool.classFilesAccept(
+            new AllMemberInfoVisitor(
+            new MemberInfoNameConflictFilter(
+            new MultiMemberInfoVisitor(new MemberInfoVisitor[]
+            {
+                new MemberInfoNameCleaner(),
+                new MemberInfoObfuscator(configuration.overloadAggressively,
+                                         new SpecialNameFactory(new SimpleNameFactory()),
+                                         descriptorMap),
+            }))));
+
+        descriptorMap.clear();
 
         // Print out the mapping, if requested.
         if (configuration.printMapping != null)
@@ -691,12 +921,12 @@ public class ProGuard
             if (configuration.verbose)
             {
                 System.out.println("Printing mapping" +
-                                   (configuration.printMapping.length() > 0 ?
-                                       " to [" + configuration.printMapping + "]" :
+                                   (isFile(configuration.printMapping) ?
+                                       " to [" + configuration.printMapping.getAbsolutePath() + "]" :
                                        "..."));
             }
 
-            PrintStream ps = configuration.printMapping.length() > 0 ?
+            PrintStream ps = isFile(configuration.printMapping) ?
                 new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.printMapping))) :
                 System.out;
 
@@ -709,9 +939,26 @@ public class ProGuard
             }
         }
 
-        // Actually apply these new names.
-        programClassPool.classFilesAccept(new ClassFileRenamer(configuration.defaultPackage != null,
-                                                               configuration.newSourceFileAttribute));
+        // Actually apply the new names.
+        programClassPool.classFilesAccept(new ClassFileRenamer());
+        libraryClassPool.classFilesAccept(new ClassFileRenamer());
+
+        // Update all references to these new names.
+        programClassPool.classFilesAccept(new ClassFileReferenceFixer());
+        libraryClassPool.classFilesAccept(new ClassFileReferenceFixer());
+        programClassPool.classFilesAccept(new MemberReferenceFixer(1024));
+
+        // Make package visible elements public, if necessary.
+        if (configuration.defaultPackage != null)
+        {
+            programClassPool.classFilesAccept(new ClassFileOpener());
+        }
+
+        // Rename the source file attributes, if requested.
+        if (configuration.newSourceFileAttribute != null)
+        {
+            programClassPool.classFilesAccept(new SourceFileRenamer(configuration.newSourceFileAttribute));
+        }
 
         // Mark NameAndType constant pool entries that have to be kept
         // and remove the other ones.
@@ -730,6 +977,7 @@ public class ProGuard
      */
     private void sortConstantPools()
     {
+        // TODO: Avoid duplicate constant pool entries.
         programClassPool.classFilesAccept(new ConstantPoolSorter(1024));
     }
 
@@ -778,7 +1026,7 @@ public class ProGuard
                     ClassPathEntry otherEntry = programJars.get(inIndex);
 
                     if (!otherEntry.isOutput() &&
-                        entry.getName().equals(otherEntry.getName()))
+                        entry.getFile().equals(otherEntry.getFile()))
                     {
                         throw new IOException("The output jar [" + entry.getName() +
                                               "] must be different from all input jars.");
@@ -849,7 +1097,7 @@ public class ProGuard
                                     new DataEntryCopier(writer));
 
             // Read and handle the specified input entries.
-            readInput("Copying resources from program ",
+            readInput("  Copying resources from program ",
                       classPath,
                       fromInputIndex,
                       fromOutputIndex,
@@ -873,18 +1121,18 @@ public class ProGuard
         if (configuration.verbose)
         {
             System.out.println("Printing classes" +
-                               (configuration.dump.length() > 0 ?
-                                   " to [" + configuration.dump + "]" :
+                               (isFile(configuration.dump) ?
+                                   " to [" + configuration.dump.getAbsolutePath() + "]" :
                                    "..."));
         }
 
-        PrintStream ps = configuration.dump.length() > 0 ?
+        PrintStream ps = isFile(configuration.dump) ?
             new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.dump))) :
             System.out;
 
         programClassPool.classFilesAccept(new ClassFilePrinter(ps));
 
-        if (configuration.dump.length() > 0)
+        if (isFile(configuration.dump))
         {
             ps.close();
         }
@@ -892,6 +1140,15 @@ public class ProGuard
 
 
     /**
+     * Returns whether the given file is actually a file, or just a placeholder
+     * for the standard output.
+     */
+    private boolean isFile(File file){
+        return file.getPath().length() > 0;
+    }
+
+
+    /**
      * The main method for ProGuard.
      */
     public static void main(String[] args)
@@ -909,11 +1166,19 @@ public class ProGuard
         {
             // Parse the options specified in the command line arguments.
             ConfigurationParser parser = new ConfigurationParser(args);
-            parser.parse(configuration);
 
-            // Execute ProGuard with these options.
-            ProGuard proGuard = new ProGuard(configuration);
-            proGuard.execute();
+            try
+            {
+                parser.parse(configuration);
+
+                // Execute ProGuard with these options.
+                ProGuard proGuard = new ProGuard(configuration);
+                proGuard.execute();
+            }
+            finally
+            {
+                parser.close();
+            }
         }
         catch (Exception ex)
         {
diff --git a/src/proguard/SubclassedClassFileFilter.java b/src/proguard/SubclassedClassFileFilter.java
index 128bd84..b74dba7 100644
--- a/src/proguard/SubclassedClassFileFilter.java
+++ b/src/proguard/SubclassedClassFileFilter.java
@@ -1,8 +1,8 @@
-/* $Id: SubclassedClassFileFilter.java,v 1.10 2004/08/15 12:39:30 eric Exp $
+/* $Id: SubclassedClassFileFilter.java,v 1.11 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/WordReader.java b/src/proguard/WordReader.java
index 4827335..7eaa554 100644
--- a/src/proguard/WordReader.java
+++ b/src/proguard/WordReader.java
@@ -1,8 +1,8 @@
-/* $Id: WordReader.java,v 1.15 2004/11/20 15:41:24 eric Exp $
+/* $Id: WordReader.java,v 1.20 2005/06/11 14:50:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -36,6 +36,7 @@ public abstract class WordReader
     private static final char COMMENT_CHARACTER = '#';
 
 
+    private File       baseDir;
     private WordReader includeWordReader;
     private String     currentLine;
     private int        currentLineLength;
@@ -45,6 +46,42 @@ public abstract class WordReader
 
 
     /**
+     * Creates a new WordReader with the given base directory.
+     */
+    protected WordReader(File baseDir)
+    {
+        this.baseDir = baseDir;
+    }
+
+
+    /**
+     * Sets the base directory of this reader.
+     */
+    public void setBaseDir(File baseDir)
+    {
+        if (includeWordReader != null)
+        {
+            includeWordReader.setBaseDir(baseDir);
+        }
+        else
+        {
+            this.baseDir = baseDir;
+        }
+    }
+
+
+    /**
+     * Returns the base directory of this reader, if any.
+     */
+    public File getBaseDir()
+    {
+        return includeWordReader != null ?
+            includeWordReader.getBaseDir() :
+            baseDir;
+    }
+
+
+    /**
      * Specifies to start reading words from the given WordReader. When it is
      * exhausted, this WordReader will continue to provide its own words.
      *
@@ -84,7 +121,8 @@ public abstract class WordReader
                 return currentWord;
             }
 
-            // Otherwise ditch the word reader.
+            // Otherwise close and ditch the word reader.
+            includeWordReader.close();
             includeWordReader = null;
         }
 
@@ -243,13 +281,29 @@ public abstract class WordReader
 
 
     /**
-     * Constructs a readable description of the current WordReader position.
+     * Returns a readable description of the current WordReader position.
      *
      * @return the description.
      */
     protected abstract String lineLocationDescription();
 
 
+    /**
+     * Closes the FileWordReader.
+     */
+    public void close() throws IOException
+    {
+        // Close and ditch the included word reader, if any.
+        if (includeWordReader != null)
+        {
+            includeWordReader.close();
+            includeWordReader = null;
+        }
+    }
+
+
+    // Small utility methods.
+
     private boolean isDelimiter(char character)
     {
         return character == '@' ||
diff --git a/src/proguard/ant/ClassMemberSpecificationElement.java b/src/proguard/ant/ClassMemberSpecificationElement.java
index 062fe62..5f8ba37 100644
--- a/src/proguard/ant/ClassMemberSpecificationElement.java
+++ b/src/proguard/ant/ClassMemberSpecificationElement.java
@@ -1,8 +1,8 @@
-/* $Id: ClassMemberSpecificationElement.java,v 1.4 2004/11/20 15:41:24 eric Exp $
+/* $Id: ClassMemberSpecificationElement.java,v 1.5 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/ant/ClassPathElement.java b/src/proguard/ant/ClassPathElement.java
index e1d687a..654831b 100644
--- a/src/proguard/ant/ClassPathElement.java
+++ b/src/proguard/ant/ClassPathElement.java
@@ -1,8 +1,8 @@
-/* $Id: ClassPathElement.java,v 1.7 2004/12/18 20:21:11 eric Exp $
+/* $Id: ClassPathElement.java,v 1.9 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -60,8 +60,8 @@ public class ClassPathElement extends Path
      */
     public void appendClassPathEntriesTo(ClassPath classPath, boolean output)
     {
-        String   basePath = "";
-        String[] files;
+        File     baseDir = getProject().getBaseDir();
+        String[] fileNames;
 
         if (isReference())
         {
@@ -74,7 +74,7 @@ public class ClassPathElement extends Path
                 Path path = (Path)referencedObject;
 
                 // Get the names of the files in the referenced path.
-                files = path.list();
+                fileNames = path.list();
             }
             else if (referencedObject instanceof AbstractFileSet)
             {
@@ -82,8 +82,8 @@ public class ClassPathElement extends Path
 
                 // Get the names of the existing input files in the referenced file set.
                 DirectoryScanner scanner = fileSet.getDirectoryScanner(getProject());
-                basePath = scanner.getBasedir().getPath() + File.separator;
-                files    = scanner.getIncludedFiles();
+                baseDir   = scanner.getBasedir();
+                fileNames = scanner.getIncludedFiles();
             }
             else
             {
@@ -93,14 +93,19 @@ public class ClassPathElement extends Path
         else
         {
             // Get the names of the files in this path.
-            files = list();
+            fileNames = list();
         }
 
-        for (int index = 0; index < files.length; index++)
+        for (int index = 0; index < fileNames.length; index++)
         {
             // Create a new class path entry, with the proper file name and
             // any filters.
-            ClassPathEntry entry = new ClassPathEntry(basePath + files[index], output);
+            String fileName = fileNames[index];
+            File   file     = new File(fileName);
+
+            ClassPathEntry entry =
+                new ClassPathEntry(file.isAbsolute() ? file : new File(baseDir, fileName),
+                                   output);
             entry.setFilter(filter);
             entry.setJarFilter(jarFilter);
             entry.setWarFilter(warFilter);
diff --git a/src/proguard/ant/ClassSpecificationElement.java b/src/proguard/ant/ClassSpecificationElement.java
index 7da58af..49ce274 100644
--- a/src/proguard/ant/ClassSpecificationElement.java
+++ b/src/proguard/ant/ClassSpecificationElement.java
@@ -1,8 +1,8 @@
-/* $Id: ClassSpecificationElement.java,v 1.3 2004/12/18 20:21:43 eric Exp $
+/* $Id: ClassSpecificationElement.java,v 1.4 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/ant/ConfigurationElement.java b/src/proguard/ant/ConfigurationElement.java
index e0ff9b1..09f1358 100644
--- a/src/proguard/ant/ConfigurationElement.java
+++ b/src/proguard/ant/ConfigurationElement.java
@@ -1,8 +1,8 @@
-/* $Id: ConfigurationElement.java,v 1.1 2004/08/28 16:37:12 eric Exp $
+/* $Id: ConfigurationElement.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/ant/ConfigurationTask.java b/src/proguard/ant/ConfigurationTask.java
index 8ddbc96..5bbff11 100644
--- a/src/proguard/ant/ConfigurationTask.java
+++ b/src/proguard/ant/ConfigurationTask.java
@@ -1,8 +1,8 @@
-/* $Id: ConfigurationTask.java,v 1.3 2004/10/31 16:28:32 eric Exp $
+/* $Id: ConfigurationTask.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -141,6 +141,24 @@ public class ConfigurationTask extends Task
     }
 
 
+    public void addConfiguredWhyareyoukeeping(ClassSpecificationElement classSpecificationElement)
+    {
+        configuration.whyAreYouKeeping = extendClassSpecifications(configuration.whyAreYouKeeping,
+                                                                   classSpecificationElement,
+                                                                   true,
+                                                                   false);
+    }
+
+
+    public void addConfiguredAssumenosideeffects(ClassSpecificationElement classSpecificationElement)
+    {
+        configuration.assumeNoSideEffects = extendClassSpecifications(configuration.assumeNoSideEffects,
+                                                                      classSpecificationElement,
+                                                                      false,
+                                                                      false);
+    }
+
+
     public void addConfiguredKeepattribute(KeepAttributeElement keepAttributeElement)
     {
         configuration.keepAttributes = extendAttributes(configuration.keepAttributes,
@@ -161,17 +179,27 @@ public class ConfigurationTask extends Task
         try
         {
             String arg = getProject().replaceProperties(text);
-            ConfigurationParser parser = new ConfigurationParser(new String[] { arg });
-            parser.parse(configuration);
+
+            ConfigurationParser parser = new ConfigurationParser(new String[] { arg },
+                                                                 getProject().getBaseDir());
+
+            try
+            {
+                parser.parse(configuration);
+            }
+            catch (ParseException ex)
+            {
+                throw new BuildException(ex.getMessage());
+            }
+            finally
+            {
+                parser.close();
+            }
         }
         catch (IOException ex)
         {
             throw new BuildException(ex.getMessage());
         }
-        catch (ParseException ex)
-        {
-            throw new BuildException(ex.getMessage());
-        }
     }
 
 
diff --git a/src/proguard/ant/KeepAttributeElement.java b/src/proguard/ant/KeepAttributeElement.java
index 1ce0041..ff44e16 100644
--- a/src/proguard/ant/KeepAttributeElement.java
+++ b/src/proguard/ant/KeepAttributeElement.java
@@ -1,8 +1,8 @@
-/* $Id: KeepAttributeElement.java,v 1.2 2004/08/28 20:55:21 eric Exp $
+/* $Id: KeepAttributeElement.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/ant/ProGuardTask.java b/src/proguard/ant/ProGuardTask.java
index a88fc2e..5f5483a 100644
--- a/src/proguard/ant/ProGuardTask.java
+++ b/src/proguard/ant/ProGuardTask.java
@@ -1,8 +1,8 @@
-/* $Id: ProGuardTask.java,v 1.28 2004/11/20 15:08:57 eric Exp $
+/* $Id: ProGuardTask.java,v 1.32 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -39,17 +39,25 @@ public class ProGuardTask extends ConfigurationTask
     {
         try
         {
-            ConfigurationParser parser = new ConfigurationParser(configurationFile.getPath());
-            parser.parse(configuration);
+            ConfigurationParser parser = new ConfigurationParser(configurationFile);
+
+            try
+            {
+                parser.parse(configuration);
+            }
+            catch (ParseException ex)
+            {
+                throw new BuildException(ex.getMessage());
+            }
+            finally
+            {
+                parser.close();
+            }
         }
         catch (IOException ex)
         {
             throw new BuildException(ex.getMessage());
         }
-        catch (ParseException ex)
-        {
-            throw new BuildException(ex.getMessage());
-        }
     }
 
 
@@ -76,7 +84,7 @@ public class ProGuardTask extends ConfigurationTask
 
     public void setPrintseeds(File printSeeds)
     {
-        configuration.printSeeds = optionalFileName(printSeeds);
+        configuration.printSeeds = optionalFile(printSeeds);
     }
 
 
@@ -88,7 +96,7 @@ public class ProGuardTask extends ConfigurationTask
 
     public void setPrintusage(File printUsage)
     {
-        configuration.printUsage = optionalFileName(printUsage);
+        configuration.printUsage = optionalFile(printUsage);
     }
 
 
@@ -112,19 +120,19 @@ public class ProGuardTask extends ConfigurationTask
 
     public void setPrintmapping(File printMapping)
     {
-        configuration.printMapping = optionalFileName(printMapping);
+        configuration.printMapping = optionalFile(printMapping);
     }
 
 
-    public void setApplymapping(String applyMapping)
+    public void setApplymapping(File applyMapping)
     {
-        configuration.applyMapping = applyMapping;
+        configuration.applyMapping = resolvedFile(applyMapping);
     }
 
 
     public void setObfuscationdictionary(File obfuscationDictionary)
     {
-        configuration.obfuscationDictionary = obfuscationDictionary.getName();
+        configuration.obfuscationDictionary = resolvedFile(obfuscationDictionary);
     }
 
 
@@ -178,7 +186,7 @@ public class ProGuardTask extends ConfigurationTask
 
     public void setDump(File dump)
     {
-        configuration.dump = optionalFileName(dump);
+        configuration.dump = optionalFile(dump);
     }
 
 
@@ -200,7 +208,12 @@ public class ProGuardTask extends ConfigurationTask
 
     // Small utility methods.
 
-    private String optionalFileName(File file)
+    /**
+     * Returns a file that is properly resolved with respect to the project
+     * directory, or <code>null</code> or empty if its name is actually a
+     * boolean flag.
+     */
+    private File optionalFile(File file)
     {
         String fileName = file.getName();
 
@@ -210,7 +223,19 @@ public class ProGuardTask extends ConfigurationTask
             fileName.equalsIgnoreCase("off")    ? null :
             fileName.equalsIgnoreCase("true")  ||
             fileName.equalsIgnoreCase("yes")   ||
-            fileName.equalsIgnoreCase("on")     ? ""   :
-                                                  file.getPath();
+            fileName.equalsIgnoreCase("on")     ? new File("")   :
+                                                  resolvedFile(file);
+    }
+
+
+    /**
+     * Returns a file that is properly resolved with respect to the project
+     * directory.
+     */
+    private File resolvedFile(File file)
+    {
+        return file.isAbsolute() ? file :
+                                   new File(getProject().getBaseDir(),
+                                            file.getName());
     }
 }
diff --git a/src/proguard/classfile/ClassConstants.java b/src/proguard/classfile/ClassConstants.java
index 844d616..a1fced8 100644
--- a/src/proguard/classfile/ClassConstants.java
+++ b/src/proguard/classfile/ClassConstants.java
@@ -1,4 +1,4 @@
-/* $Id: ClassConstants.java,v 1.24 2004/12/19 21:03:54 eric Exp $
+/* $Id: ClassConstants.java,v 1.25 2005/05/22 00:30:30 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
@@ -39,54 +39,54 @@ public interface ClassConstants
     public static final int MAJOR_VERSION_MAX = 49;
     public static final int MINOR_VERSION_MAX = 0;
 
-    public static final int    INTERNAL_ACC_PUBLIC       = 0x0001;
-    public static final int    INTERNAL_ACC_PRIVATE      = 0x0002;
-    public static final int    INTERNAL_ACC_PROTECTED    = 0x0004;
-    public static final int    INTERNAL_ACC_STATIC       = 0x0008;
-    public static final int    INTERNAL_ACC_FINAL        = 0x0010;
-    public static final int    INTERNAL_ACC_SUPER        = 0x0020;
-    public static final int    INTERNAL_ACC_SYNCHRONIZED = 0x0020;
-    public static final int    INTERNAL_ACC_VOLATILE     = 0x0040;
-    public static final int    INTERNAL_ACC_TRANSIENT    = 0x0080;
-    public static final int    INTERNAL_ACC_BRIDGE       = 0x0040;
-    public static final int    INTERNAL_ACC_VARARGS      = 0x0080;
-    public static final int    INTERNAL_ACC_NATIVE       = 0x0100;
-    public static final int    INTERNAL_ACC_INTERFACE    = 0x0200;
-    public static final int    INTERNAL_ACC_ABSTRACT     = 0x0400;
-    public static final int    INTERNAL_ACC_STRICT       = 0x0800;
-    public static final int    INTERNAL_ACC_SYNTHETIC    = 0x1000;
-    public static final int    INTERNAL_ACC_ANNOTATTION  = 0x2000;
-    public static final int    INTERNAL_ACC_ENUM         = 0x4000;
-
-    public static final int    VALID_INTERNAL_ACC_CLASS  = INTERNAL_ACC_PUBLIC       |
-                                                           INTERNAL_ACC_FINAL        |
-                                                           INTERNAL_ACC_SUPER        |
-                                                           INTERNAL_ACC_INTERFACE    |
-                                                           INTERNAL_ACC_ABSTRACT     |
-                                                           INTERNAL_ACC_SYNTHETIC    |
-                                                           INTERNAL_ACC_ANNOTATTION  |
-                                                           INTERNAL_ACC_ENUM;
-    public static final int    VALID_INTERNAL_ACC_FIELD  = INTERNAL_ACC_PUBLIC       |
-                                                           INTERNAL_ACC_PRIVATE      |
-                                                           INTERNAL_ACC_PROTECTED    |
-                                                           INTERNAL_ACC_STATIC       |
-                                                           INTERNAL_ACC_FINAL        |
-                                                           INTERNAL_ACC_VOLATILE     |
-                                                           INTERNAL_ACC_TRANSIENT    |
-                                                           INTERNAL_ACC_SYNTHETIC    |
-                                                           INTERNAL_ACC_ENUM;
-    public static final int    VALID_INTERNAL_ACC_METHOD = INTERNAL_ACC_PUBLIC       |
-                                                           INTERNAL_ACC_PRIVATE      |
-                                                           INTERNAL_ACC_PROTECTED    |
-                                                           INTERNAL_ACC_STATIC       |
-                                                           INTERNAL_ACC_FINAL        |
-                                                           INTERNAL_ACC_SYNCHRONIZED |
-                                                           INTERNAL_ACC_BRIDGE       |
-                                                           INTERNAL_ACC_VARARGS      |
-                                                           INTERNAL_ACC_NATIVE       |
-                                                           INTERNAL_ACC_ABSTRACT     |
-                                                           INTERNAL_ACC_STRICT       |
-                                                           INTERNAL_ACC_SYNTHETIC;
+    public static final int INTERNAL_ACC_PUBLIC       = 0x0001;
+    public static final int INTERNAL_ACC_PRIVATE      = 0x0002;
+    public static final int INTERNAL_ACC_PROTECTED    = 0x0004;
+    public static final int INTERNAL_ACC_STATIC       = 0x0008;
+    public static final int INTERNAL_ACC_FINAL        = 0x0010;
+    public static final int INTERNAL_ACC_SUPER        = 0x0020;
+    public static final int INTERNAL_ACC_SYNCHRONIZED = 0x0020;
+    public static final int INTERNAL_ACC_VOLATILE     = 0x0040;
+    public static final int INTERNAL_ACC_TRANSIENT    = 0x0080;
+    public static final int INTERNAL_ACC_BRIDGE       = 0x0040;
+    public static final int INTERNAL_ACC_VARARGS      = 0x0080;
+    public static final int INTERNAL_ACC_NATIVE       = 0x0100;
+    public static final int INTERNAL_ACC_INTERFACE    = 0x0200;
+    public static final int INTERNAL_ACC_ABSTRACT     = 0x0400;
+    public static final int INTERNAL_ACC_STRICT       = 0x0800;
+    public static final int INTERNAL_ACC_SYNTHETIC    = 0x1000;
+    public static final int INTERNAL_ACC_ANNOTATTION  = 0x2000;
+    public static final int INTERNAL_ACC_ENUM         = 0x4000;
+
+    public static final int VALID_INTERNAL_ACC_CLASS  = INTERNAL_ACC_PUBLIC       |
+                                                        INTERNAL_ACC_FINAL        |
+                                                        INTERNAL_ACC_SUPER        |
+                                                        INTERNAL_ACC_INTERFACE    |
+                                                        INTERNAL_ACC_ABSTRACT     |
+                                                        INTERNAL_ACC_SYNTHETIC    |
+                                                        INTERNAL_ACC_ANNOTATTION  |
+                                                        INTERNAL_ACC_ENUM;
+    public static final int VALID_INTERNAL_ACC_FIELD  = INTERNAL_ACC_PUBLIC       |
+                                                        INTERNAL_ACC_PRIVATE      |
+                                                        INTERNAL_ACC_PROTECTED    |
+                                                        INTERNAL_ACC_STATIC       |
+                                                        INTERNAL_ACC_FINAL        |
+                                                        INTERNAL_ACC_VOLATILE     |
+                                                        INTERNAL_ACC_TRANSIENT    |
+                                                        INTERNAL_ACC_SYNTHETIC    |
+                                                        INTERNAL_ACC_ENUM;
+    public static final int VALID_INTERNAL_ACC_METHOD = INTERNAL_ACC_PUBLIC       |
+                                                        INTERNAL_ACC_PRIVATE      |
+                                                        INTERNAL_ACC_PROTECTED    |
+                                                        INTERNAL_ACC_STATIC       |
+                                                        INTERNAL_ACC_FINAL        |
+                                                        INTERNAL_ACC_SYNCHRONIZED |
+                                                        INTERNAL_ACC_BRIDGE       |
+                                                        INTERNAL_ACC_VARARGS      |
+                                                        INTERNAL_ACC_NATIVE       |
+                                                        INTERNAL_ACC_ABSTRACT     |
+                                                        INTERNAL_ACC_STRICT       |
+                                                        INTERNAL_ACC_SYNTHETIC;
 
     public static final String EXTERNAL_ACC_PUBLIC       = "public";
     public static final String EXTERNAL_ACC_PRIVATE      = "private";
diff --git a/src/proguard/classfile/ClassCpInfo.java b/src/proguard/classfile/ClassCpInfo.java
index 3c8c573..8996e48 100644
--- a/src/proguard/classfile/ClassCpInfo.java
+++ b/src/proguard/classfile/ClassCpInfo.java
@@ -1,9 +1,9 @@
-/* $Id: ClassCpInfo.java,v 1.20 2004/11/14 00:54:38 eric Exp $
+/* $Id: ClassCpInfo.java,v 1.21 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/ClassFile.java b/src/proguard/classfile/ClassFile.java
index e9f6b7e..b2a7d38 100644
--- a/src/proguard/classfile/ClassFile.java
+++ b/src/proguard/classfile/ClassFile.java
@@ -1,9 +1,9 @@
-/* $Id: ClassFile.java,v 1.20 2004/12/11 16:35:23 eric Exp $
+/* $Id: ClassFile.java,v 1.25 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -51,6 +51,11 @@ public interface ClassFile extends VisitorAccepter
     public String getSuperName();
 
     /**
+     * Returns the number of interfaces that this class implements.
+     */
+    public int getInterfaceCount();
+
+    /**
      * Returns the full internal name of the interface at the given index of
      * this class.
      */
@@ -182,6 +187,95 @@ public interface ClassFile extends VisitorAccepter
     public void methodAccept(String name, String descriptor, MemberInfoVisitor memberInfoVisitor);
 
     /**
+     * Returns whether the given method may possibly have implementing or
+     * overriding methods down the class hierarchy. This can only be true
+     * if the class is not final, and the method is not private, static, or
+     * final, or a constructor.
+     * @param methodInfo the method that may have implementations.
+     * @return whether it may have implementations.
+     */
+    public boolean mayHaveImplementations(MethodInfo methodInfo);
+
+    /**
+     * Lets the given member info visitor visit all concrete implementations of
+     * the specified method in the class hierarchy.
+     * @param methodInfo        the method that may have concrete implementations.
+     * @param visitThisMethod   specifies whether to visit the method in
+     *                          this class.
+     * @param memberInfoVisitor the <code>MemberInfoVisitor</code> that will
+     *                          visit the method hierarchy.
+     */
+    public void methodImplementationsAccept(MethodInfo        methodInfo,
+                                            boolean           visitThisMethod,
+                                            MemberInfoVisitor memberInfoVisitor);
+
+    /**
+     * Lets the given member info visitor visit all concrete implementations of
+     * the specified method in the class hierarchy.
+     * @param name              the method name.
+     * @param type              the method descriptor.
+     * @param visitThisMethod   specifies whether to visit the method in
+     *                          this class.
+     * @param memberInfoVisitor the <code>MemberInfoVisitor</code> that will
+     *                          visit the method hierarchy.
+     */
+    public void methodImplementationsAccept(String            name,
+                                            String            type,
+                                            boolean           visitThisMethod,
+                                            MemberInfoVisitor memberInfoVisitor);
+
+    /**
+     * Lets the given member info visitor visit all concrete implementations of
+     * the specified method in the class hierarchy.
+     * @param name                   the method name.
+     * @param type                   the method descriptor.
+     * @param visitThisMethod        specifies whether to visit the method in
+     *                               this class.
+     * @param visitSuperMethods      specifies whether to visit the method in
+     *                               the super classes.
+     * @param visitInterfaceMethods  specifies whether to visit the method in
+     *                               the interfaces.
+     * @param visitOverridingMethods specifies whether to visit the method in
+     *                               the subclasses.
+     * @param visitSpecialMethods    specifies whether to visit special methods.
+     * @param memberInfoVisitor      the <code>MemberInfoVisitor</code> that
+     *                               will visit the method hierarchy.
+     */
+    public void methodImplementationsAccept(String            name,
+                                            String            descriptor,
+                                            boolean           visitThisMethod,
+                                            boolean           visitSpecialMethods,
+                                            boolean           visitSuperMethods,
+                                            boolean           visitOverridingMethods,
+                                            MemberInfoVisitor memberInfoVisitor);
+    /**
+     * Lets the given member info visitor visit all concrete implementations of
+     * the specified method in the class hierarchy.
+     * @param name                   the method name.
+     * @param type                   the method descriptor.
+     * @param methodInfo             the method itself, if present.
+     * @param visitThisMethod        specifies whether to visit the method in
+     *                               this class.
+     * @param visitSuperMethods      specifies whether to visit the method in
+     *                               the super classes.
+     * @param visitInterfaceMethods  specifies whether to visit the method in
+     *                               the interfaces.
+     * @param visitOverridingMethods specifies whether to visit the method in
+     *                               the subclasses.
+     * @param visitSpecialMethods    specifies whether to visit special methods.
+     * @param memberInfoVisitor      the <code>MemberInfoVisitor</code> that
+     *                               will visit the method hierarchy.
+     */
+    public void methodImplementationsAccept(String            name,
+                                            String            descriptor,
+                                            MethodInfo        methodInfo,
+                                            boolean           visitThisMethod,
+                                            boolean           visitSuperMethods,
+                                            boolean           visitOverridingMethods,
+                                            boolean           visitSpecialMethods,
+                                            MemberInfoVisitor memberInfoVisitor);
+
+    /**
      * Lets the given attribute info visitor visit all attributes of this class.
      */
     public void attributesAccept(AttrInfoVisitor attrInfoVisitor);
diff --git a/src/proguard/classfile/ClassPool.java b/src/proguard/classfile/ClassPool.java
index e60728e..6a7a9a6 100644
--- a/src/proguard/classfile/ClassPool.java
+++ b/src/proguard/classfile/ClassPool.java
@@ -1,9 +1,9 @@
-/* $Id: ClassPool.java,v 1.16 2004/10/23 16:53:00 eric Exp $
+/* $Id: ClassPool.java,v 1.18 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -115,7 +115,14 @@ public class ClassPool
         while (iterator.hasNext())
         {
             ClassFile classFile = (ClassFile)iterator.next();
+try{
             classFile.accept(classFileVisitor);
+}catch (RuntimeException ex) {
+    System.out.println("Runtime exception while processing class file ["+classFile.getName()+"]");
+    throw ex;
+}catch (Error er) {
+    System.out.println("Runtime error while processing class file ["+classFile.getName()+"]");
+    throw er;}
         }
     }
 
diff --git a/src/proguard/classfile/CpInfo.java b/src/proguard/classfile/CpInfo.java
index 81c3cbe..b3229c6 100644
--- a/src/proguard/classfile/CpInfo.java
+++ b/src/proguard/classfile/CpInfo.java
@@ -1,9 +1,9 @@
-/* $Id: CpInfo.java,v 1.22 2004/10/23 16:53:00 eric Exp $
+/* $Id: CpInfo.java,v 1.23 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/DoubleCpInfo.java b/src/proguard/classfile/DoubleCpInfo.java
index b309649..ac5f5b3 100644
--- a/src/proguard/classfile/DoubleCpInfo.java
+++ b/src/proguard/classfile/DoubleCpInfo.java
@@ -1,9 +1,9 @@
-/* $Id: DoubleCpInfo.java,v 1.17 2004/10/23 16:53:00 eric Exp $
+/* $Id: DoubleCpInfo.java,v 1.18 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/FieldInfo.java b/src/proguard/classfile/FieldInfo.java
index 9c7607b..ba85840 100644
--- a/src/proguard/classfile/FieldInfo.java
+++ b/src/proguard/classfile/FieldInfo.java
@@ -1,9 +1,9 @@
-/* $Id: FieldInfo.java,v 1.12 2004/10/23 16:53:00 eric Exp $
+/* $Id: FieldInfo.java,v 1.13 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/FieldrefCpInfo.java b/src/proguard/classfile/FieldrefCpInfo.java
index 1ff608b..f4ec471 100644
--- a/src/proguard/classfile/FieldrefCpInfo.java
+++ b/src/proguard/classfile/FieldrefCpInfo.java
@@ -1,9 +1,9 @@
-/* $Id: FieldrefCpInfo.java,v 1.20 2004/10/23 16:53:00 eric Exp $
+/* $Id: FieldrefCpInfo.java,v 1.21 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/FloatCpInfo.java b/src/proguard/classfile/FloatCpInfo.java
index 2218446..1d9fffd 100644
--- a/src/proguard/classfile/FloatCpInfo.java
+++ b/src/proguard/classfile/FloatCpInfo.java
@@ -1,9 +1,9 @@
-/* $Id: FloatCpInfo.java,v 1.16 2004/10/23 16:53:00 eric Exp $
+/* $Id: FloatCpInfo.java,v 1.17 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/IntegerCpInfo.java b/src/proguard/classfile/IntegerCpInfo.java
index eec5f50..855667c 100644
--- a/src/proguard/classfile/IntegerCpInfo.java
+++ b/src/proguard/classfile/IntegerCpInfo.java
@@ -1,9 +1,9 @@
-/* $Id: IntegerCpInfo.java,v 1.16 2004/10/23 16:53:00 eric Exp $
+/* $Id: IntegerCpInfo.java,v 1.17 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/InterfaceMethodrefCpInfo.java b/src/proguard/classfile/InterfaceMethodrefCpInfo.java
index a9c229b..2840763 100644
--- a/src/proguard/classfile/InterfaceMethodrefCpInfo.java
+++ b/src/proguard/classfile/InterfaceMethodrefCpInfo.java
@@ -1,9 +1,9 @@
-/* $Id: InterfaceMethodrefCpInfo.java,v 1.20 2004/11/07 18:49:09 eric Exp $
+/* $Id: InterfaceMethodrefCpInfo.java,v 1.21 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/LibraryClassFile.java b/src/proguard/classfile/LibraryClassFile.java
index 1f6af92..65fc671 100644
--- a/src/proguard/classfile/LibraryClassFile.java
+++ b/src/proguard/classfile/LibraryClassFile.java
@@ -1,9 +1,9 @@
-/* $Id: LibraryClassFile.java,v 1.35 2004/12/11 16:35:23 eric Exp $
+/* $Id: LibraryClassFile.java,v 1.40 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -278,46 +278,6 @@ public class LibraryClassFile implements ClassFile
     }
 
 
-    /**
-     * Returns the field with the given name and descriptor.
-     */
-    private LibraryFieldInfo findLibraryField(String name, String descriptor)
-    {
-        for (int i = 0; i < fields.length; i++)
-        {
-            LibraryFieldInfo field = fields[i];
-            if (field != null &&
-                (name       == null || field.getName(this).equals(name)) &&
-                (descriptor == null || field.getDescriptor(this).equals(descriptor)))
-            {
-                return field;
-            }
-        }
-
-        return null;
-    }
-
-
-    /**
-     * Returns the method with the given name and descriptor.
-     */
-    private LibraryMethodInfo findLibraryMethod(String name, String descriptor)
-    {
-        for (int i = 0; i < methods.length; i++)
-        {
-            LibraryMethodInfo method = methods[i];
-            if (method != null &&
-                (name       == null || method.getName(this).equals(name)) &&
-                (descriptor == null || method.getDescriptor(this).equals(descriptor)))
-            {
-                return method;
-            }
-        }
-
-        return null;
-    }
-
-
     // Implementations for ClassFile.
 
     public int getAccessFlags()
@@ -336,6 +296,11 @@ public class LibraryClassFile implements ClassFile
         return superClassName;
     }
 
+    public int getInterfaceCount()
+    {
+        return interfaceClasses.length;
+    }
+
     public String getInterfaceName(int index)
     {
         return interfaceNames[index];
@@ -421,7 +386,7 @@ public class LibraryClassFile implements ClassFile
         {
             for (int i = 0; i < interfaceClasses.length; i++)
             {
-                ClassFile interfaceClass = getInterface(i);
+                ClassFile interfaceClass = interfaceClasses[i];
                 if (interfaceClass != null &&
                     interfaceClass.implements_(classFile))
                 {
@@ -436,13 +401,35 @@ public class LibraryClassFile implements ClassFile
 
     public FieldInfo findField(String name, String descriptor)
     {
-        return findLibraryField(name, descriptor);
+        for (int i = 0; i < fields.length; i++)
+        {
+            FieldInfo field = fields[i];
+            if (field != null &&
+                (name       == null || field.getName(this).equals(name)) &&
+                (descriptor == null || field.getDescriptor(this).equals(descriptor)))
+            {
+                return field;
+            }
+        }
+
+        return null;
     }
 
 
     public MethodInfo findMethod(String name, String descriptor)
     {
-        return findLibraryMethod(name, descriptor);
+        for (int i = 0; i < methods.length; i++)
+        {
+            MethodInfo method = methods[i];
+            if (method != null &&
+                (name       == null || method.getName(this).equals(name)) &&
+                (descriptor == null || method.getDescriptor(this).equals(descriptor)))
+            {
+                return method;
+            }
+        }
+
+        return null;
     }
 
 
@@ -484,7 +471,7 @@ public class LibraryClassFile implements ClassFile
             {
                 for (int i = 0; i < interfaceClasses.length; i++)
                 {
-                    ClassFile interfaceClass = getInterface(i);
+                    ClassFile interfaceClass = interfaceClasses[i];
                     if (interfaceClass != null)
                     {
                         interfaceClass.hierarchyAccept(true,
@@ -521,11 +508,13 @@ public class LibraryClassFile implements ClassFile
         // This class doesn't keep references to its constant pool entries.
     }
 
+
     public void constantPoolEntryAccept(int index, CpInfoVisitor cpInfoVisitor)
     {
         // This class doesn't keep references to its constant pool entries.
     }
 
+
     public void fieldsAccept(MemberInfoVisitor memberInfoVisitor)
     {
         for (int i = 0; i < fields.length; i++)
@@ -537,15 +526,17 @@ public class LibraryClassFile implements ClassFile
         }
     }
 
+
     public void fieldAccept(String name, String descriptor, MemberInfoVisitor memberInfoVisitor)
     {
-        LibraryMemberInfo libraryMemberInfo = findLibraryField(name, descriptor);
-        if (libraryMemberInfo != null)
+        FieldInfo field = findField(name, descriptor);
+        if (field != null)
         {
-            libraryMemberInfo.accept(this, memberInfoVisitor);
+            field.accept(this, memberInfoVisitor);
         }
     }
 
+
     public void methodsAccept(MemberInfoVisitor memberInfoVisitor)
     {
         for (int i = 0; i < methods.length; i++)
@@ -557,15 +548,181 @@ public class LibraryClassFile implements ClassFile
         }
     }
 
+
     public void methodAccept(String name, String descriptor, MemberInfoVisitor memberInfoVisitor)
     {
-        LibraryMemberInfo libraryMemberInfo = findLibraryMethod(name, descriptor);
-        if (libraryMemberInfo != null)
+        MethodInfo method = findMethod(name, descriptor);
+        if (method != null)
         {
-            libraryMemberInfo.accept(this, memberInfoVisitor);
+            method.accept(this, memberInfoVisitor);
         }
     }
 
+
+    public boolean mayHaveImplementations(MethodInfo methodInfo)
+    {
+        return
+           (u2accessFlags & ClassConstants.INTERNAL_ACC_FINAL) == 0 &&
+           (methodInfo == null ||
+            ((methodInfo.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PRIVATE |
+                                             ClassConstants.INTERNAL_ACC_STATIC  |
+                                             ClassConstants.INTERNAL_ACC_FINAL)) == 0 &&
+             !methodInfo.getName(this).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)));
+    }
+
+
+    private boolean isSpecial(MethodInfo methodInfo)
+    {
+        return
+            (methodInfo.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PRIVATE |
+                                            ClassConstants.INTERNAL_ACC_STATIC)) != 0 ||
+            methodInfo.getName(this).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT);
+    }
+
+
+    public void methodImplementationsAccept(MethodInfo        methodInfo,
+                                            boolean           visitThisMethod,
+                                            MemberInfoVisitor memberInfoVisitor)
+    {
+        methodImplementationsAccept(methodInfo.getName(this),
+                                    methodInfo.getDescriptor(this),
+                                    methodInfo,
+                                    visitThisMethod,
+                                    true,
+                                    true,
+                                    true,
+                                    memberInfoVisitor);
+    }
+
+
+    public void methodImplementationsAccept(String            name,
+                                            String            descriptor,
+                                            boolean           visitThisMethod,
+                                            MemberInfoVisitor memberInfoVisitor)
+    {
+        methodImplementationsAccept(name,
+                                    descriptor,
+                                    visitThisMethod,
+                                    true,
+                                    true,
+                                    true,
+                                    memberInfoVisitor);
+    }
+
+
+    public void methodImplementationsAccept(String            name,
+                                            String            descriptor,
+                                            boolean           visitThisMethod,
+                                            boolean           visitSpecialMethods,
+                                            boolean           visitSuperMethods,
+                                            boolean           visitOverridingMethods,
+                                            MemberInfoVisitor memberInfoVisitor)
+    {
+        methodImplementationsAccept(name,
+                                    descriptor,
+                                    findMethod(name, descriptor),
+                                    visitThisMethod,
+                                    visitSpecialMethods,
+                                    visitSuperMethods,
+                                    visitOverridingMethods,
+                                    memberInfoVisitor);
+    }
+
+
+    public void methodImplementationsAccept(String            name,
+                                            String            descriptor,
+                                            MethodInfo        methodInfo,
+                                            boolean           visitThisMethod,
+                                            boolean           visitSpecialMethods,
+                                            boolean           visitSuperMethods,
+                                            boolean           visitOverridingMethods,
+                                            MemberInfoVisitor memberInfoVisitor)
+    {
+        // Do we have the method in this class?
+        if (methodInfo != null)
+        {
+            // Is it a special method?
+            if (isSpecial(methodInfo))
+            {
+                // Visit the special method in this class, if allowed.
+                if (visitSpecialMethods)
+                {
+                    methodInfo.accept(this, memberInfoVisitor);
+
+                    // The method can't have any other implementations.
+                    return;
+                }
+            }
+            else
+            {
+                // Visit the method in this class, if allowed.
+                if (visitThisMethod)
+                {
+                    methodInfo.accept(this, memberInfoVisitor);
+                }
+
+                // We don't have to look in subclasses if there can't be
+                // any overriding implementations.
+                if (!mayHaveImplementations(methodInfo))
+                {
+                    visitOverridingMethods = false;
+                }
+
+                // We don't have to look in superclasses if we have a concrete
+                // implementation here.
+                if ((methodInfo.getAccessFlags() & ClassConstants.INTERNAL_ACC_ABSTRACT) == 0)
+                {
+                    visitSuperMethods = false;
+                }
+            }
+        }
+
+        // Then visit the method in its subclasses, recursively.
+        if (visitOverridingMethods)
+        {
+            // Go looking for implementations in all of the subclasses.
+            if (subClasses != null)
+            {
+                for (int i = 0; i < subClasses.length; i++)
+                {
+                    ClassFile subClass = subClasses[i];
+                    subClass.methodImplementationsAccept(name,
+                                                         descriptor,
+                                                         true,
+                                                         false,
+                                                         visitSuperMethods,
+                                                         true,
+                                                         memberInfoVisitor);
+                }
+            }
+
+            // We don't have to look in superclasses right away if we dont't
+            // have a concrete class here.
+            if ((u2accessFlags & (ClassConstants.INTERNAL_ACC_INTERFACE |
+                                  ClassConstants.INTERNAL_ACC_ABSTRACT)) != 0)
+            {
+                visitSuperMethods = false;
+            }
+        }
+
+        // Then visit the method in its superclass, recursively.
+        if (visitSuperMethods)
+        {
+            ClassFile superClass = getSuperClass();
+            if (superClass != null)
+            {
+                superClass.methodImplementationsAccept(name,
+                                                       descriptor,
+                                                       true,
+                                                       false,
+                                                       true,
+                                                       false,
+                                                       memberInfoVisitor);
+            }
+        }
+    }
+
+
     public void attributesAccept(AttrInfoVisitor attrInfoVisitor)
     {
         // This class doesn't keep references to its attributes.
diff --git a/src/proguard/classfile/LibraryFieldInfo.java b/src/proguard/classfile/LibraryFieldInfo.java
index f7f0472..880fc6c 100644
--- a/src/proguard/classfile/LibraryFieldInfo.java
+++ b/src/proguard/classfile/LibraryFieldInfo.java
@@ -1,9 +1,9 @@
-/* $Id: LibraryFieldInfo.java,v 1.14 2004/10/23 16:53:00 eric Exp $
+/* $Id: LibraryFieldInfo.java,v 1.16 2005/06/25 22:07:51 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -33,6 +33,13 @@ import java.io.*;
  */
 public class LibraryFieldInfo extends LibraryMemberInfo implements FieldInfo
 {
+    /**
+     * An extra field pointing to the ClassFile object referenced in the
+     * descriptor string. This field is filled out by the <code>{@link
+     * proguard.classfile.util.ClassFileReferenceInitializer ClassFileReferenceInitializer}</code>.
+     * References to primitive types are ignored.
+     */
+    public ClassFile referencedClassFile;
 
 
     /**
@@ -47,6 +54,12 @@ public class LibraryFieldInfo extends LibraryMemberInfo implements FieldInfo
         return fi;
     }
 
+
+    protected LibraryFieldInfo()
+    {
+    }
+
+
     /**
      * Accepts the given visitor.
      */
@@ -54,7 +67,4 @@ public class LibraryFieldInfo extends LibraryMemberInfo implements FieldInfo
     {
         memberInfoVisitor.visitLibraryFieldInfo(libraryClassFile, this);
     }
-
-
-    protected LibraryFieldInfo() {}
 }
diff --git a/src/proguard/classfile/LibraryMemberInfo.java b/src/proguard/classfile/LibraryMemberInfo.java
index c52b2c2..bd5310e 100644
--- a/src/proguard/classfile/LibraryMemberInfo.java
+++ b/src/proguard/classfile/LibraryMemberInfo.java
@@ -1,9 +1,9 @@
-/* $Id: LibraryMemberInfo.java,v 1.21 2004/10/23 16:53:00 eric Exp $
+/* $Id: LibraryMemberInfo.java,v 1.22 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/LibraryMethodInfo.java b/src/proguard/classfile/LibraryMethodInfo.java
index 00e4242..9d3ef9d 100644
--- a/src/proguard/classfile/LibraryMethodInfo.java
+++ b/src/proguard/classfile/LibraryMethodInfo.java
@@ -1,9 +1,9 @@
-/* $Id: LibraryMethodInfo.java,v 1.14 2004/10/23 16:53:00 eric Exp $
+/* $Id: LibraryMethodInfo.java,v 1.16 2005/06/25 22:07:51 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -33,6 +33,13 @@ import java.io.*;
  */
 public class LibraryMethodInfo extends LibraryMemberInfo implements MethodInfo
 {
+    /**
+     * An extra field pointing to the ClassFile objects referenced in the
+     * descriptor string. This field is filled out by the <code>{@link
+     * proguard.classfile.util.ClassFileReferenceInitializer ClassFileReferenceInitializer}</code>.
+     * References to primitive types are ignored.
+     */
+    public ClassFile[] referencedClassFiles;
 
 
     /**
@@ -47,6 +54,12 @@ public class LibraryMethodInfo extends LibraryMemberInfo implements MethodInfo
         return mi;
     }
 
+
+    protected LibraryMethodInfo()
+    {
+    }
+
+
     /**
      * Accepts the given visitor.
      */
@@ -54,7 +67,4 @@ public class LibraryMethodInfo extends LibraryMemberInfo implements MethodInfo
     {
         memberInfoVisitor.visitLibraryMethodInfo(libraryClassFile, this);
     }
-
-
-    protected LibraryMethodInfo() {}
 }
diff --git a/src/proguard/classfile/LongCpInfo.java b/src/proguard/classfile/LongCpInfo.java
index 9935962..bec79d0 100644
--- a/src/proguard/classfile/LongCpInfo.java
+++ b/src/proguard/classfile/LongCpInfo.java
@@ -1,9 +1,9 @@
-/* $Id: LongCpInfo.java,v 1.16 2004/10/23 16:53:00 eric Exp $
+/* $Id: LongCpInfo.java,v 1.17 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/MemberInfo.java b/src/proguard/classfile/MemberInfo.java
index 420f5c2..93fb9d6 100644
--- a/src/proguard/classfile/MemberInfo.java
+++ b/src/proguard/classfile/MemberInfo.java
@@ -1,9 +1,9 @@
-/* $Id: MemberInfo.java,v 1.19 2004/10/23 16:53:00 eric Exp $
+/* $Id: MemberInfo.java,v 1.20 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/MethodInfo.java b/src/proguard/classfile/MethodInfo.java
index c0bde5a..3b040e6 100644
--- a/src/proguard/classfile/MethodInfo.java
+++ b/src/proguard/classfile/MethodInfo.java
@@ -1,9 +1,9 @@
-/* $Id: MethodInfo.java,v 1.12 2004/10/23 16:53:01 eric Exp $
+/* $Id: MethodInfo.java,v 1.13 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/MethodrefCpInfo.java b/src/proguard/classfile/MethodrefCpInfo.java
index 4c317fc..6cd267a 100644
--- a/src/proguard/classfile/MethodrefCpInfo.java
+++ b/src/proguard/classfile/MethodrefCpInfo.java
@@ -1,9 +1,9 @@
-/* $Id: MethodrefCpInfo.java,v 1.20 2004/10/23 16:53:01 eric Exp $
+/* $Id: MethodrefCpInfo.java,v 1.21 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/NameAndTypeCpInfo.java b/src/proguard/classfile/NameAndTypeCpInfo.java
index b10404d..b0ad21d 100644
--- a/src/proguard/classfile/NameAndTypeCpInfo.java
+++ b/src/proguard/classfile/NameAndTypeCpInfo.java
@@ -1,9 +1,9 @@
-/* $Id: NameAndTypeCpInfo.java,v 1.19 2004/10/23 16:53:01 eric Exp $
+/* $Id: NameAndTypeCpInfo.java,v 1.21 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -36,14 +36,6 @@ public class NameAndTypeCpInfo extends CpInfo implements Cloneable
     public int u2nameIndex;
     public int u2descriptorIndex;
 
-    /**
-     * An extra field pointing to the ClassFile objects referenced in the
-     * descriptor string. This field is filled out by the <code>{@link
-     * proguard.classfile.util.ClassFileReferenceInitializer ClassFileReferenceInitializer}</code>.
-     * References to primitive types are ignored.
-     */
-    public ClassFile[] referencedClassFiles;
-
 
     protected NameAndTypeCpInfo()
     {
@@ -52,19 +44,15 @@ public class NameAndTypeCpInfo extends CpInfo implements Cloneable
 
     /**
      * Creates a new NameAndTypeCpInfo with the given name and type indices.
-     * @param u2nameIndex          the index of the name in the constant pool.
-     * @param u2descriptorIndex    the index of the descriptor in the constant
-     *                             pool.
-     * @param referencedClassFiles the list of class files referenced in the
-     *                             descriptor string.
+     * @param u2nameIndex       the index of the name in the constant pool.
+     * @param u2descriptorIndex the index of the descriptor in the constant
+     *                          pool.
      */
-    public NameAndTypeCpInfo(int         u2nameIndex,
-                             int         u2descriptorIndex,
-                             ClassFile[] referencedClassFiles)
+    public NameAndTypeCpInfo(int u2nameIndex,
+                             int u2descriptorIndex)
     {
-        this.u2nameIndex          = u2nameIndex;
-        this.u2descriptorIndex    = u2descriptorIndex;
-        this.referencedClassFiles = referencedClassFiles;
+        this.u2nameIndex       = u2nameIndex;
+        this.u2descriptorIndex = u2descriptorIndex;
     }
 
 
@@ -140,23 +128,4 @@ public class NameAndTypeCpInfo extends CpInfo implements Cloneable
     {
         cpInfoVisitor.visitNameAndTypeCpInfo(classFile, this);
     }
-
-
-    /**
-     * Lets the ClassFile objects referenced in the descriptor string
-     * accept the given visitor.
-     */
-    public void referencedClassesAccept(ClassFileVisitor classFileVisitor)
-    {
-        if (referencedClassFiles != null)
-        {
-            for (int i = 0; i < referencedClassFiles.length; i++)
-            {
-                if (referencedClassFiles[i] != null)
-                {
-                    referencedClassFiles[i].accept(classFileVisitor);
-                }
-            }
-        }
-    }
 }
diff --git a/src/proguard/classfile/ProgramClassFile.java b/src/proguard/classfile/ProgramClassFile.java
index 54d1a19..a97cb14 100644
--- a/src/proguard/classfile/ProgramClassFile.java
+++ b/src/proguard/classfile/ProgramClassFile.java
@@ -1,9 +1,9 @@
-/* $Id: ProgramClassFile.java,v 1.32 2004/12/11 16:35:23 eric Exp $
+/* $Id: ProgramClassFile.java,v 1.37 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -127,34 +127,46 @@ public class ProgramClassFile implements ClassFile
 
         // Read the interfaces.
         u2interfacesCount = din.readUnsignedShort();
-        u2interfaces      = new int[u2interfacesCount];
-        for (int i = 0; i < u2interfacesCount; i++)
+        if (u2interfacesCount > 0)
         {
-            u2interfaces[i] = din.readUnsignedShort();
+            u2interfaces = new int[u2interfacesCount];
+            for (int i = 0; i < u2interfacesCount; i++)
+            {
+                u2interfaces[i] = din.readUnsignedShort();
+            }
         }
 
         // Read the fields.
         u2fieldsCount = din.readUnsignedShort();
-        fields        = new ProgramFieldInfo[u2fieldsCount];
-        for (int i = 0; i < u2fieldsCount; i++)
+        if (u2fieldsCount > 0)
         {
-            fields[i] = ProgramFieldInfo.create(din, this);
+            fields = new ProgramFieldInfo[u2fieldsCount];
+            for (int i = 0; i < u2fieldsCount; i++)
+            {
+                fields[i] = ProgramFieldInfo.create(din, this);
+            }
         }
 
         // Read the methods.
         u2methodsCount = din.readUnsignedShort();
-        methods        = new ProgramMethodInfo[u2methodsCount];
-        for (int i = 0; i < u2methodsCount; i++)
+        if (u2methodsCount > 0)
         {
-            methods[i] = ProgramMethodInfo.create(din, this);
+            methods = new ProgramMethodInfo[u2methodsCount];
+            for (int i = 0; i < u2methodsCount; i++)
+            {
+                methods[i] = ProgramMethodInfo.create(din, this);
+            }
         }
 
         // Read the attributes.
         u2attributesCount = din.readUnsignedShort();
-        attributes        = new AttrInfo[u2attributesCount];
-        for (int i = 0; i < u2attributesCount; i++)
+        if (u2attributesCount > 0)
         {
-            attributes[i] = AttrInfo.create(din, this);
+            attributes = new AttrInfo[u2attributesCount];
+            for (int i = 0; i < u2attributesCount; i++)
+            {
+                attributes[i] = AttrInfo.create(din, this);
+            }
         }
     }
 
@@ -212,44 +224,6 @@ public class ProgramClassFile implements ClassFile
 
 
     /**
-     * Returns the field with the given name and descriptor.
-     */
-    ProgramFieldInfo findProgramField(String name, String descriptor)
-    {
-        for (int i = 0; i < u2fieldsCount; i++)
-        {
-            ProgramFieldInfo field = fields[i];
-            if ((name       == null || field.getName(this).equals(name)) &&
-                (descriptor == null || field.getDescriptor(this).equals(descriptor)))
-            {
-                return field;
-            }
-        }
-
-        return null;
-    }
-
-
-    /**
-     * Returns the method with the given name and descriptor.
-     */
-    ProgramMethodInfo findProgramMethod(String name, String descriptor)
-    {
-        for (int i = 0; i < u2methodsCount; i++)
-        {
-            ProgramMethodInfo method = methods[i];
-            if ((name       == null || method.getName(this).equals(name)) &&
-                (descriptor == null || method.getDescriptor(this).equals(descriptor)))
-            {
-                return method;
-            }
-        }
-
-        return null;
-    }
-
-
-    /**
      * Returns the attribute specified by the given name.
      */
     AttrInfo getAttribute(String name)
@@ -284,6 +258,11 @@ public class ProgramClassFile implements ClassFile
         return u2superClass == 0 ? null : getCpClassNameString(u2superClass);
     }
 
+    public int getInterfaceCount()
+    {
+        return u2interfacesCount;
+    }
+
     public String getInterfaceName(int index)
     {
         return getCpClassNameString(u2interfaces[index]);
@@ -386,13 +365,33 @@ public class ProgramClassFile implements ClassFile
 
     public FieldInfo findField(String name, String descriptor)
     {
-        return findProgramField(name, descriptor);
+        for (int i = 0; i < u2fieldsCount; i++)
+        {
+            FieldInfo field = fields[i];
+            if ((name       == null || field.getName(this).equals(name)) &&
+                (descriptor == null || field.getDescriptor(this).equals(descriptor)))
+            {
+                return field;
+            }
+        }
+
+        return null;
     }
 
 
     public MethodInfo findMethod(String name, String descriptor)
     {
-        return findProgramMethod(name, descriptor);
+        for (int i = 0; i < u2methodsCount; i++)
+        {
+            MethodInfo method = methods[i];
+            if ((name       == null || method.getName(this).equals(name)) &&
+                (descriptor == null || method.getDescriptor(this).equals(descriptor)))
+            {
+                return method;
+            }
+        }
+
+        return null;
     }
 
 
@@ -475,11 +474,13 @@ public class ProgramClassFile implements ClassFile
         }
     }
 
+
     public void constantPoolEntryAccept(int index, CpInfoVisitor cpInfoVisitor)
     {
         constantPool[index].accept(this, cpInfoVisitor);
     }
 
+
     public void fieldsAccept(MemberInfoVisitor memberInfoVisitor)
     {
         for (int i = 0; i < u2fieldsCount; i++)
@@ -488,15 +489,17 @@ public class ProgramClassFile implements ClassFile
         }
     }
 
+
     public void fieldAccept(String name, String descriptor, MemberInfoVisitor memberInfoVisitor)
     {
-        ProgramFieldInfo field = findProgramField(name, descriptor);
+        FieldInfo field = findField(name, descriptor);
         if (field != null)
         {
             field.accept(this, memberInfoVisitor);
         }
     }
 
+
     public void methodsAccept(MemberInfoVisitor memberInfoVisitor)
     {
         for (int i = 0; i < u2methodsCount; i++)
@@ -505,15 +508,181 @@ public class ProgramClassFile implements ClassFile
         }
     }
 
+
     public void methodAccept(String name, String descriptor, MemberInfoVisitor memberInfoVisitor)
     {
-        ProgramMethodInfo method = findProgramMethod(name, descriptor);
+        MethodInfo method = findMethod(name, descriptor);
         if (method != null)
         {
             method.accept(this, memberInfoVisitor);
         }
     }
 
+
+    public boolean mayHaveImplementations(MethodInfo methodInfo)
+    {
+        return
+           (u2accessFlags & ClassConstants.INTERNAL_ACC_FINAL) == 0 &&
+           (methodInfo == null ||
+            ((methodInfo.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PRIVATE |
+                                             ClassConstants.INTERNAL_ACC_STATIC  |
+                                             ClassConstants.INTERNAL_ACC_FINAL)) == 0 &&
+             !methodInfo.getName(this).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)));
+    }
+
+
+    private boolean isSpecial(MethodInfo methodInfo)
+    {
+        return
+            (methodInfo.getAccessFlags() & (ClassConstants.INTERNAL_ACC_PRIVATE |
+                                            ClassConstants.INTERNAL_ACC_STATIC)) != 0 ||
+            methodInfo.getName(this).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT);
+    }
+
+
+    public void methodImplementationsAccept(MethodInfo        methodInfo,
+                                            boolean           visitThisMethod,
+                                            MemberInfoVisitor memberInfoVisitor)
+    {
+        methodImplementationsAccept(methodInfo.getName(this),
+                                    methodInfo.getDescriptor(this),
+                                    methodInfo,
+                                    visitThisMethod,
+                                    true,
+                                    true,
+                                    true,
+                                    memberInfoVisitor);
+    }
+
+
+    public void methodImplementationsAccept(String            name,
+                                            String            descriptor,
+                                            boolean           visitThisMethod,
+                                            MemberInfoVisitor memberInfoVisitor)
+    {
+        methodImplementationsAccept(name,
+                                    descriptor,
+                                    visitThisMethod,
+                                    true,
+                                    true,
+                                    true,
+                                    memberInfoVisitor);
+    }
+
+
+    public void methodImplementationsAccept(String            name,
+                                            String            descriptor,
+                                            boolean           visitThisMethod,
+                                            boolean           visitSpecialMethods,
+                                            boolean           visitSuperMethods,
+                                            boolean           visitOverridingMethods,
+                                            MemberInfoVisitor memberInfoVisitor)
+    {
+        methodImplementationsAccept(name,
+                                    descriptor,
+                                    findMethod(name, descriptor),
+                                    visitThisMethod,
+                                    visitSpecialMethods,
+                                    visitSuperMethods,
+                                    visitOverridingMethods,
+                                    memberInfoVisitor);
+    }
+
+
+    public void methodImplementationsAccept(String            name,
+                                            String            descriptor,
+                                            MethodInfo        methodInfo,
+                                            boolean           visitThisMethod,
+                                            boolean           visitSpecialMethods,
+                                            boolean           visitSuperMethods,
+                                            boolean           visitOverridingMethods,
+                                            MemberInfoVisitor memberInfoVisitor)
+    {
+        // Do we have the method in this class?
+        if (methodInfo != null)
+        {
+            // Is it a special method?
+            if (isSpecial(methodInfo))
+            {
+                // Visit the special method in this class, if allowed.
+                if (visitSpecialMethods)
+                {
+                    methodInfo.accept(this, memberInfoVisitor);
+
+                    // The method can't have any other implementations.
+                    return;
+                }
+            }
+            else
+            {
+                // Visit the method in this class, if allowed.
+                if (visitThisMethod)
+                {
+                    methodInfo.accept(this, memberInfoVisitor);
+                }
+
+                // We don't have to look in subclasses if there can't be
+                // any overriding implementations.
+                if (!mayHaveImplementations(methodInfo))
+                {
+                    visitOverridingMethods = false;
+                }
+
+                // We don't have to look in superclasses if we have a concrete
+                // implementation here.
+                if ((methodInfo.getAccessFlags() & ClassConstants.INTERNAL_ACC_ABSTRACT) == 0)
+                {
+                    visitSuperMethods = false;
+                }
+            }
+        }
+
+        // Then visit the method in its subclasses, recursively.
+        if (visitOverridingMethods)
+        {
+            // Go looking for implementations in all of the subclasses.
+            if (subClasses != null)
+            {
+                for (int i = 0; i < subClasses.length; i++)
+                {
+                    ClassFile subClass = subClasses[i];
+                    subClass.methodImplementationsAccept(name,
+                                                         descriptor,
+                                                         true,
+                                                         false,
+                                                         visitSuperMethods,
+                                                         true,
+                                                         memberInfoVisitor);
+                }
+            }
+
+            // We don't have to look in superclasses right away if we dont't
+            // have a concrete class here.
+            if ((u2accessFlags & (ClassConstants.INTERNAL_ACC_INTERFACE |
+                                  ClassConstants.INTERNAL_ACC_ABSTRACT)) != 0)
+            {
+                visitSuperMethods = false;
+            }
+        }
+
+        // Then visit the method in its superclass, recursively.
+        if (visitSuperMethods)
+        {
+            ClassFile superClass = getSuperClass();
+            if (superClass != null)
+            {
+                superClass.methodImplementationsAccept(name,
+                                                       descriptor,
+                                                       true,
+                                                       false,
+                                                       true,
+                                                       false,
+                                                       memberInfoVisitor);
+            }
+        }
+    }
+
+
     public void attributesAccept(AttrInfoVisitor attrInfoVisitor)
     {
         for (int i = 0; i < u2attributesCount; i++)
diff --git a/src/proguard/classfile/ProgramFieldInfo.java b/src/proguard/classfile/ProgramFieldInfo.java
index f36993f..828988a 100644
--- a/src/proguard/classfile/ProgramFieldInfo.java
+++ b/src/proguard/classfile/ProgramFieldInfo.java
@@ -1,9 +1,9 @@
-/* $Id: ProgramFieldInfo.java,v 1.16 2004/10/23 16:53:01 eric Exp $
+/* $Id: ProgramFieldInfo.java,v 1.18 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -35,6 +35,15 @@ import java.io.*;
 public class ProgramFieldInfo extends ProgramMemberInfo implements FieldInfo
 {
     /**
+     * An extra field pointing to the ClassFile object referenced in the
+     * descriptor string. This field is filled out by the <code>{@link
+     * proguard.classfile.util.ClassFileReferenceInitializer ClassFileReferenceInitializer}</code>.
+     * References to primitive types are ignored.
+     */
+    public ClassFile referencedClassFile;
+
+
+    /**
      * Creates a new ProgramFieldInfo from the file format data in the DataInput stream.
      *
      * @throws IOException if class file is corrupt or incomplete
@@ -67,4 +76,13 @@ public class ProgramFieldInfo extends ProgramMemberInfo implements FieldInfo
             attributes[i].accept(programClassFile, this, attrInfoVisitor);
         }
     }
+
+
+    public void referencedClassesAccept(ClassFileVisitor classFileVisitor)
+    {
+        if (referencedClassFile != null)
+        {
+            referencedClassFile.accept(classFileVisitor);
+        }
+    }
 }
diff --git a/src/proguard/classfile/ProgramMemberInfo.java b/src/proguard/classfile/ProgramMemberInfo.java
index 7b3bade..1f2e637 100644
--- a/src/proguard/classfile/ProgramMemberInfo.java
+++ b/src/proguard/classfile/ProgramMemberInfo.java
@@ -1,9 +1,9 @@
-/* $Id: ProgramMemberInfo.java,v 1.27 2004/11/14 00:54:38 eric Exp $
+/* $Id: ProgramMemberInfo.java,v 1.29 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -42,14 +42,6 @@ abstract public class ProgramMemberInfo implements MemberInfo
     public AttrInfo[] attributes;
 
     /**
-     * An extra field pointing to the ClassFile objects referenced in the
-     * descriptor string. This field is filled out by the <code>{@link
-     * proguard.classfile.util.ClassFileReferenceInitializer ClassFileReferenceInitializer}</code>.
-     * References to primitive types are ignored.
-     */
-    public ClassFile[] referencedClassFiles;
-
-    /**
      * An extra field in which visitors can store information.
      */
     public Object visitorInfo;
@@ -124,19 +116,7 @@ abstract public class ProgramMemberInfo implements MemberInfo
      * Lets the ClassFile objects referenced in the descriptor string
      * accept the given visitor.
      */
-    public void referencedClassesAccept(ClassFileVisitor classFileVisitor)
-    {
-        if (referencedClassFiles != null)
-        {
-            for (int i = 0; i < referencedClassFiles.length; i++)
-            {
-                if (referencedClassFiles[i] != null)
-                {
-                    referencedClassFiles[i].accept(classFileVisitor);
-                }
-            }
-        }
-    }
+    public abstract void referencedClassesAccept(ClassFileVisitor classFileVisitor);
 
 
     /**
@@ -148,10 +128,13 @@ abstract public class ProgramMemberInfo implements MemberInfo
         u2nameIndex = din.readUnsignedShort();
         u2descriptorIndex = din.readUnsignedShort();
         u2attributesCount = din.readUnsignedShort();
-        attributes = new AttrInfo[u2attributesCount];
-        for (int i = 0; i < u2attributesCount; i++)
+        if (u2attributesCount > 0)
         {
-            attributes[i] = AttrInfo.create(din, cf);
+            attributes = new AttrInfo[u2attributesCount];
+            for (int i = 0; i < u2attributesCount; i++)
+            {
+                attributes[i] = AttrInfo.create(din, cf);
+            }
         }
     }
 
diff --git a/src/proguard/classfile/ProgramMethodInfo.java b/src/proguard/classfile/ProgramMethodInfo.java
index b46a733..b7ee3c6 100644
--- a/src/proguard/classfile/ProgramMethodInfo.java
+++ b/src/proguard/classfile/ProgramMethodInfo.java
@@ -1,9 +1,9 @@
-/* $Id: ProgramMethodInfo.java,v 1.16 2004/10/23 16:53:01 eric Exp $
+/* $Id: ProgramMethodInfo.java,v 1.19 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -35,6 +35,15 @@ import java.io.*;
 public class ProgramMethodInfo extends ProgramMemberInfo implements MethodInfo
 {
     /**
+     * An extra field pointing to the ClassFile objects referenced in the
+     * descriptor string. This field is filled out by the <code>{@link
+     * proguard.classfile.util.ClassFileReferenceInitializer ClassFileReferenceInitializer}</code>.
+     * References to primitive types are ignored.
+     */
+    public ClassFile[] referencedClassFiles;
+
+
+    /**
      * Creates a new ProgramMethodInfo from the file format data in the DataInput stream.
      *
      * @throws IOException if class file is corrupt or incomplete
@@ -67,4 +76,19 @@ public class ProgramMethodInfo extends ProgramMemberInfo implements MethodInfo
             attributes[i].accept(programClassFile, this, attrInfoVisitor);
         }
     }
+
+
+    public void referencedClassesAccept(ClassFileVisitor classFileVisitor)
+    {
+        if (referencedClassFiles != null)
+        {
+            for (int i = 0; i < referencedClassFiles.length; i++)
+            {
+                if (referencedClassFiles[i] != null)
+                {
+                    referencedClassFiles[i].accept(classFileVisitor);
+                }
+            }
+        }
+    }
 }
diff --git a/src/proguard/classfile/RefCpInfo.java b/src/proguard/classfile/RefCpInfo.java
index 37b2637..af939af 100644
--- a/src/proguard/classfile/RefCpInfo.java
+++ b/src/proguard/classfile/RefCpInfo.java
@@ -1,9 +1,9 @@
-/* $Id: RefCpInfo.java,v 1.21 2004/10/31 18:13:37 eric Exp $
+/* $Id: RefCpInfo.java,v 1.22 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/StringCpInfo.java b/src/proguard/classfile/StringCpInfo.java
index 9fd8021..9b094ac 100644
--- a/src/proguard/classfile/StringCpInfo.java
+++ b/src/proguard/classfile/StringCpInfo.java
@@ -1,9 +1,9 @@
-/* $Id: StringCpInfo.java,v 1.17 2004/11/07 18:49:09 eric Exp $
+/* $Id: StringCpInfo.java,v 1.18 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/Utf8CpInfo.java b/src/proguard/classfile/Utf8CpInfo.java
index 35faa3d..f84e672 100644
--- a/src/proguard/classfile/Utf8CpInfo.java
+++ b/src/proguard/classfile/Utf8CpInfo.java
@@ -1,9 +1,9 @@
-/* $Id: Utf8CpInfo.java,v 1.20 2004/10/23 16:53:01 eric Exp $
+/* $Id: Utf8CpInfo.java,v 1.21 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/VisitorAccepter.java b/src/proguard/classfile/VisitorAccepter.java
index d5d8b31..7bb10d4 100644
--- a/src/proguard/classfile/VisitorAccepter.java
+++ b/src/proguard/classfile/VisitorAccepter.java
@@ -1,9 +1,9 @@
-/* $Id: VisitorAccepter.java,v 1.11 2004/10/23 16:53:01 eric Exp $
+/* $Id: VisitorAccepter.java,v 1.12 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/AllAttrInfoVisitor.java b/src/proguard/classfile/attribute/AllAttrInfoVisitor.java
index ca8582e..6ace2ab 100644
--- a/src/proguard/classfile/attribute/AllAttrInfoVisitor.java
+++ b/src/proguard/classfile/attribute/AllAttrInfoVisitor.java
@@ -1,4 +1,4 @@
-/* $Id: AllAttrInfoVisitor.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: AllAttrInfoVisitor.java,v 1.2 2005/05/22 00:29:17 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
@@ -21,16 +21,21 @@
 package proguard.classfile.attribute;
 
 import proguard.classfile.*;
+import proguard.classfile.attribute.annotation.*;
 import proguard.classfile.visitor.*;
 
 
 /**
- * This MemberInfoVisitor lets a given AttrInfoVisitor visit all AttrInfo
- * objects of the program class members it visits.
+ * This ClassFileVisitor and MemberInfoVisitor lets a given AttrInfoVisitor
+ * visit all AttrInfo objects of the program classes and program class members
+ * it visits.
  *
  * @author Eric Lafortune
  */
-public class AllAttrInfoVisitor implements MemberInfoVisitor
+public class AllAttrInfoVisitor
+implements   ClassFileVisitor,
+             MemberInfoVisitor,
+             AttrInfoVisitor
 {
     private AttrInfoVisitor attrInfoVisitor;
 
@@ -41,17 +46,42 @@ public class AllAttrInfoVisitor implements MemberInfoVisitor
     }
 
 
+    // Implementations for ClassFileVisitor.
+
+    public void visitProgramClassFile(ProgramClassFile programClassFile)
+    {
+        // Visit the attributes of all fields and methods.
+        programClassFile.fieldsAccept(this);
+        programClassFile.methodsAccept(this);
+
+        // Visit the attributes.
+        programClassFile.attributesAccept(attrInfoVisitor);
+    }
+
+
+    public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+    {
+        // Library class files don't have attributes.
+    }
+
+
     // Implementations for MemberInfoVisitor.
 
     public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
     {
         programFieldInfo.attributesAccept(programClassFile, attrInfoVisitor);
+
+        // Visit the attributes.
+        programFieldInfo.attributesAccept(programClassFile, this);
     }
 
 
     public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
         programMethodInfo.attributesAccept(programClassFile, attrInfoVisitor);
+
+        // Visit the attributes.
+        programMethodInfo.attributesAccept(programClassFile, this);
     }
 
 
@@ -65,4 +95,33 @@ public class AllAttrInfoVisitor implements MemberInfoVisitor
     {
         // Library class file methods don't have attributes.
     }
+
+
+    // Implementations for AttrInfoVisitor.
+
+    public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+    public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+    public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
+    public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+    public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+    public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+    public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
+    public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
+    public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+    public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+    public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+    public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+    public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
+    public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo) {}
+    public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo) {}
+    public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo) {}
+    public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo) {}
+    public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {}
+
+
+    public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+    {
+        // Visit the attributes.
+        codeAttrInfo.attributesAccept(classFile, methodInfo, this);
+    }
 }
diff --git a/src/proguard/classfile/attribute/AttrInfo.java b/src/proguard/classfile/attribute/AttrInfo.java
index c7a0b31..056e57f 100644
--- a/src/proguard/classfile/attribute/AttrInfo.java
+++ b/src/proguard/classfile/attribute/AttrInfo.java
@@ -1,9 +1,9 @@
-/* $Id: AttrInfo.java,v 1.3 2004/11/26 17:19:58 eric Exp $
+/* $Id: AttrInfo.java,v 1.4 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/AttrInfoVisitor.java b/src/proguard/classfile/attribute/AttrInfoVisitor.java
index 3388d37..db5ba3b 100644
--- a/src/proguard/classfile/attribute/AttrInfoVisitor.java
+++ b/src/proguard/classfile/attribute/AttrInfoVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: AttrInfoVisitor.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: AttrInfoVisitor.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -21,7 +21,6 @@
 package proguard.classfile.attribute;
 
 import proguard.classfile.*;
-import proguard.classfile.attribute.*;
 import proguard.classfile.attribute.annotation.*;
 
 /**
diff --git a/src/proguard/classfile/attribute/CodeAttrInfo.java b/src/proguard/classfile/attribute/CodeAttrInfo.java
index 9e89d83..b092965 100644
--- a/src/proguard/classfile/attribute/CodeAttrInfo.java
+++ b/src/proguard/classfile/attribute/CodeAttrInfo.java
@@ -1,9 +1,9 @@
-/* $Id: CodeAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: CodeAttrInfo.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -22,10 +22,8 @@
 package proguard.classfile.attribute;
 
 
-import proguard.classfile.instruction.*;
-import proguard.classfile.visitor.*;
-import proguard.classfile.attribute.*;
 import proguard.classfile.*;
+import proguard.classfile.instruction.*;
 
 import java.io.*;
 
diff --git a/src/proguard/classfile/attribute/DeprecatedAttrInfo.java b/src/proguard/classfile/attribute/DeprecatedAttrInfo.java
index d45d692..24ebd51 100644
--- a/src/proguard/classfile/attribute/DeprecatedAttrInfo.java
+++ b/src/proguard/classfile/attribute/DeprecatedAttrInfo.java
@@ -1,9 +1,9 @@
-/* $Id: DeprecatedAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: DeprecatedAttrInfo.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/EnclosingMethodAttrInfo.java b/src/proguard/classfile/attribute/EnclosingMethodAttrInfo.java
index 1587550..7f00fd6 100644
--- a/src/proguard/classfile/attribute/EnclosingMethodAttrInfo.java
+++ b/src/proguard/classfile/attribute/EnclosingMethodAttrInfo.java
@@ -1,9 +1,9 @@
-/* $Id: EnclosingMethodAttrInfo.java,v 1.2 2004/10/31 18:13:38 eric Exp $
+/* $Id: EnclosingMethodAttrInfo.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/ExceptionInfo.java b/src/proguard/classfile/attribute/ExceptionInfo.java
index b289343..bae6bf6 100644
--- a/src/proguard/classfile/attribute/ExceptionInfo.java
+++ b/src/proguard/classfile/attribute/ExceptionInfo.java
@@ -1,9 +1,9 @@
-/* $Id: ExceptionInfo.java,v 1.2 2004/11/20 15:41:24 eric Exp $
+/* $Id: ExceptionInfo.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/ExceptionInfoVisitor.java b/src/proguard/classfile/attribute/ExceptionInfoVisitor.java
index e692133..abff86c 100644
--- a/src/proguard/classfile/attribute/ExceptionInfoVisitor.java
+++ b/src/proguard/classfile/attribute/ExceptionInfoVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: ExceptionInfoVisitor.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: ExceptionInfoVisitor.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/ExceptionsAttrInfo.java b/src/proguard/classfile/attribute/ExceptionsAttrInfo.java
index d465543..2268fec 100644
--- a/src/proguard/classfile/attribute/ExceptionsAttrInfo.java
+++ b/src/proguard/classfile/attribute/ExceptionsAttrInfo.java
@@ -1,9 +1,9 @@
-/* $Id: ExceptionsAttrInfo.java,v 1.2 2004/12/11 16:35:23 eric Exp $
+/* $Id: ExceptionsAttrInfo.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/InnerClassesAttrInfo.java b/src/proguard/classfile/attribute/InnerClassesAttrInfo.java
index 174a028..5c2f629 100644
--- a/src/proguard/classfile/attribute/InnerClassesAttrInfo.java
+++ b/src/proguard/classfile/attribute/InnerClassesAttrInfo.java
@@ -1,9 +1,9 @@
-/* $Id: InnerClassesAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: InnerClassesAttrInfo.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/InnerClassesInfo.java b/src/proguard/classfile/attribute/InnerClassesInfo.java
index 51b3bb0..dac0a70 100644
--- a/src/proguard/classfile/attribute/InnerClassesInfo.java
+++ b/src/proguard/classfile/attribute/InnerClassesInfo.java
@@ -1,9 +1,9 @@
-/* $Id: InnerClassesInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: InnerClassesInfo.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/InnerClassesInfoVisitor.java b/src/proguard/classfile/attribute/InnerClassesInfoVisitor.java
index aa3a7b8..de3b05c 100644
--- a/src/proguard/classfile/attribute/InnerClassesInfoVisitor.java
+++ b/src/proguard/classfile/attribute/InnerClassesInfoVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: InnerClassesInfoVisitor.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: InnerClassesInfoVisitor.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/LibraryAttrInfo.java b/src/proguard/classfile/attribute/LibraryAttrInfo.java
index 579ce04..ad12694 100644
--- a/src/proguard/classfile/attribute/LibraryAttrInfo.java
+++ b/src/proguard/classfile/attribute/LibraryAttrInfo.java
@@ -1,9 +1,9 @@
-/* $Id: LibraryAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: LibraryAttrInfo.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/LineNumberInfo.java b/src/proguard/classfile/attribute/LineNumberInfo.java
index cc48492..0d7542b 100644
--- a/src/proguard/classfile/attribute/LineNumberInfo.java
+++ b/src/proguard/classfile/attribute/LineNumberInfo.java
@@ -1,9 +1,9 @@
-/* $Id: LineNumberInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: LineNumberInfo.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/LineNumberTableAttrInfo.java b/src/proguard/classfile/attribute/LineNumberTableAttrInfo.java
index 48d0d4b..0d4ca07 100644
--- a/src/proguard/classfile/attribute/LineNumberTableAttrInfo.java
+++ b/src/proguard/classfile/attribute/LineNumberTableAttrInfo.java
@@ -1,9 +1,9 @@
-/* $Id: LineNumberTableAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: LineNumberTableAttrInfo.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/LocalVariableInfo.java b/src/proguard/classfile/attribute/LocalVariableInfo.java
index 0108794..531b435 100644
--- a/src/proguard/classfile/attribute/LocalVariableInfo.java
+++ b/src/proguard/classfile/attribute/LocalVariableInfo.java
@@ -1,9 +1,9 @@
-/* $Id: LocalVariableInfo.java,v 1.2 2004/11/14 00:54:38 eric Exp $
+/* $Id: LocalVariableInfo.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/LocalVariableInfoVisitor.java b/src/proguard/classfile/attribute/LocalVariableInfoVisitor.java
index 088675b..2337f2c 100644
--- a/src/proguard/classfile/attribute/LocalVariableInfoVisitor.java
+++ b/src/proguard/classfile/attribute/LocalVariableInfoVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: LocalVariableInfoVisitor.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: LocalVariableInfoVisitor.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/LocalVariableTableAttrInfo.java b/src/proguard/classfile/attribute/LocalVariableTableAttrInfo.java
index 107b806..fdb630b 100644
--- a/src/proguard/classfile/attribute/LocalVariableTableAttrInfo.java
+++ b/src/proguard/classfile/attribute/LocalVariableTableAttrInfo.java
@@ -1,9 +1,9 @@
-/* $Id: LocalVariableTableAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: LocalVariableTableAttrInfo.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/LocalVariableTypeInfo.java b/src/proguard/classfile/attribute/LocalVariableTypeInfo.java
index 5453992..db9924e 100644
--- a/src/proguard/classfile/attribute/LocalVariableTypeInfo.java
+++ b/src/proguard/classfile/attribute/LocalVariableTypeInfo.java
@@ -1,9 +1,9 @@
-/* $Id: LocalVariableTypeInfo.java,v 1.2 2004/11/14 00:54:38 eric Exp $
+/* $Id: LocalVariableTypeInfo.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/LocalVariableTypeInfoVisitor.java b/src/proguard/classfile/attribute/LocalVariableTypeInfoVisitor.java
index f3666c4..f6f4999 100644
--- a/src/proguard/classfile/attribute/LocalVariableTypeInfoVisitor.java
+++ b/src/proguard/classfile/attribute/LocalVariableTypeInfoVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: LocalVariableTypeInfoVisitor.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: LocalVariableTypeInfoVisitor.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/LocalVariableTypeTableAttrInfo.java b/src/proguard/classfile/attribute/LocalVariableTypeTableAttrInfo.java
index c500a06..e3846c3 100644
--- a/src/proguard/classfile/attribute/LocalVariableTypeTableAttrInfo.java
+++ b/src/proguard/classfile/attribute/LocalVariableTypeTableAttrInfo.java
@@ -1,9 +1,9 @@
-/* $Id: LocalVariableTypeTableAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: LocalVariableTypeTableAttrInfo.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/MultiAttrInfoVisitor.java b/src/proguard/classfile/attribute/MultiAttrInfoVisitor.java
index 5fcbcfa..4e76ee7 100644
--- a/src/proguard/classfile/attribute/MultiAttrInfoVisitor.java
+++ b/src/proguard/classfile/attribute/MultiAttrInfoVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: MultiAttrInfoVisitor.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: MultiAttrInfoVisitor.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/SignatureAttrInfo.java b/src/proguard/classfile/attribute/SignatureAttrInfo.java
index 18a7f16..74d11c6 100644
--- a/src/proguard/classfile/attribute/SignatureAttrInfo.java
+++ b/src/proguard/classfile/attribute/SignatureAttrInfo.java
@@ -1,9 +1,9 @@
-/* $Id: SignatureAttrInfo.java,v 1.2 2004/11/14 00:54:38 eric Exp $
+/* $Id: SignatureAttrInfo.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/SourceDirAttrInfo.java b/src/proguard/classfile/attribute/SourceDirAttrInfo.java
index 1edf2bf..8e55146 100644
--- a/src/proguard/classfile/attribute/SourceDirAttrInfo.java
+++ b/src/proguard/classfile/attribute/SourceDirAttrInfo.java
@@ -1,9 +1,9 @@
-/* $Id: SourceDirAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: SourceDirAttrInfo.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/SourceFileAttrInfo.java b/src/proguard/classfile/attribute/SourceFileAttrInfo.java
index 8f6ff9e..c3ef70c 100644
--- a/src/proguard/classfile/attribute/SourceFileAttrInfo.java
+++ b/src/proguard/classfile/attribute/SourceFileAttrInfo.java
@@ -1,9 +1,9 @@
-/* $Id: SourceFileAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: SourceFileAttrInfo.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/SyntheticAttrInfo.java b/src/proguard/classfile/attribute/SyntheticAttrInfo.java
index c0fb2f9..7ba5a30 100644
--- a/src/proguard/classfile/attribute/SyntheticAttrInfo.java
+++ b/src/proguard/classfile/attribute/SyntheticAttrInfo.java
@@ -1,9 +1,9 @@
-/* $Id: SyntheticAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: SyntheticAttrInfo.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/UnknownAttrInfo.java b/src/proguard/classfile/attribute/UnknownAttrInfo.java
index 5811766..2ee01a9 100644
--- a/src/proguard/classfile/attribute/UnknownAttrInfo.java
+++ b/src/proguard/classfile/attribute/UnknownAttrInfo.java
@@ -1,9 +1,9 @@
-/* $Id: UnknownAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: UnknownAttrInfo.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/annotation/Annotation.java b/src/proguard/classfile/attribute/annotation/Annotation.java
index 76cea29..105c4a3 100644
--- a/src/proguard/classfile/attribute/annotation/Annotation.java
+++ b/src/proguard/classfile/attribute/annotation/Annotation.java
@@ -1,8 +1,8 @@
-/* $Id: Annotation.java,v 1.3 2004/11/20 15:41:24 eric Exp $
+/* $Id: Annotation.java,v 1.4 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/annotation/AnnotationDefaultAttrInfo.java b/src/proguard/classfile/attribute/annotation/AnnotationDefaultAttrInfo.java
index 37925cd..9b6a4dd 100644
--- a/src/proguard/classfile/attribute/annotation/AnnotationDefaultAttrInfo.java
+++ b/src/proguard/classfile/attribute/annotation/AnnotationDefaultAttrInfo.java
@@ -1,8 +1,8 @@
-/* $Id: AnnotationDefaultAttrInfo.java,v 1.3 2004/11/20 15:41:24 eric Exp $
+/* $Id: AnnotationDefaultAttrInfo.java,v 1.4 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/annotation/AnnotationElementValue.java b/src/proguard/classfile/attribute/annotation/AnnotationElementValue.java
index 256c100..9c9b2c9 100644
--- a/src/proguard/classfile/attribute/annotation/AnnotationElementValue.java
+++ b/src/proguard/classfile/attribute/annotation/AnnotationElementValue.java
@@ -1,9 +1,9 @@
-/* $Id: AnnotationElementValue.java,v 1.3 2004/11/20 15:41:24 eric Exp $
+/* $Id: AnnotationElementValue.java,v 1.4 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/annotation/AnnotationVisitor.java b/src/proguard/classfile/attribute/annotation/AnnotationVisitor.java
index 21892ec..bfb784f 100644
--- a/src/proguard/classfile/attribute/annotation/AnnotationVisitor.java
+++ b/src/proguard/classfile/attribute/annotation/AnnotationVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: AnnotationVisitor.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: AnnotationVisitor.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/annotation/ArrayElementValue.java b/src/proguard/classfile/attribute/annotation/ArrayElementValue.java
index e3ebbcb..e972551 100644
--- a/src/proguard/classfile/attribute/annotation/ArrayElementValue.java
+++ b/src/proguard/classfile/attribute/annotation/ArrayElementValue.java
@@ -1,9 +1,9 @@
-/* $Id: ArrayElementValue.java,v 1.2 2004/11/14 00:54:38 eric Exp $
+/* $Id: ArrayElementValue.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/annotation/ClassElementValue.java b/src/proguard/classfile/attribute/annotation/ClassElementValue.java
index 7778a03..1551a72 100644
--- a/src/proguard/classfile/attribute/annotation/ClassElementValue.java
+++ b/src/proguard/classfile/attribute/annotation/ClassElementValue.java
@@ -1,9 +1,9 @@
-/* $Id: ClassElementValue.java,v 1.2 2004/11/14 00:54:38 eric Exp $
+/* $Id: ClassElementValue.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/annotation/ConstantElementValue.java b/src/proguard/classfile/attribute/annotation/ConstantElementValue.java
index 2c3997b..c5d9b3e 100644
--- a/src/proguard/classfile/attribute/annotation/ConstantElementValue.java
+++ b/src/proguard/classfile/attribute/annotation/ConstantElementValue.java
@@ -1,9 +1,9 @@
-/* $Id: ConstantElementValue.java,v 1.2 2004/11/14 00:54:38 eric Exp $
+/* $Id: ConstantElementValue.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/annotation/ElementValue.java b/src/proguard/classfile/attribute/annotation/ElementValue.java
index d4754fb..92cd996 100644
--- a/src/proguard/classfile/attribute/annotation/ElementValue.java
+++ b/src/proguard/classfile/attribute/annotation/ElementValue.java
@@ -1,8 +1,8 @@
-/* $Id: ElementValue.java,v 1.4 2004/11/27 10:09:26 eric Exp $
+/* $Id: ElementValue.java,v 1.6 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -106,6 +106,15 @@ public abstract class ElementValue implements VisitorAccepter
     }
 
 
+    /**
+     * Returns the element name.
+     */
+    public String getMethodName(ClassFile classFile)
+    {
+        return classFile.getCpString(u2elementName);
+    }
+
+
     // Abstract methods to be implemented by extensions.
 
     /**
diff --git a/src/proguard/classfile/attribute/annotation/ElementValueVisitor.java b/src/proguard/classfile/attribute/annotation/ElementValueVisitor.java
index 2bc4b29..e80abc0 100644
--- a/src/proguard/classfile/attribute/annotation/ElementValueVisitor.java
+++ b/src/proguard/classfile/attribute/annotation/ElementValueVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: ElementValueVisitor.java,v 1.2 2004/11/14 00:54:38 eric Exp $
+/* $Id: ElementValueVisitor.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/attribute/annotation/EnumConstantElementValue.java b/src/proguard/classfile/attribute/annotation/EnumConstantElementValue.java
index 21be5d5..f3f61ad 100644
--- a/src/proguard/classfile/attribute/annotation/EnumConstantElementValue.java
+++ b/src/proguard/classfile/attribute/annotation/EnumConstantElementValue.java
@@ -1,9 +1,9 @@
-/* $Id: EnumConstantElementValue.java,v 1.2 2004/11/14 00:54:38 eric Exp $
+/* $Id: EnumConstantElementValue.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
  * Copyright (c) 1999      Mark Welsh (markw at retrologic.com)
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/annotation/RuntimeAnnotationsAttrInfo.java b/src/proguard/classfile/attribute/annotation/RuntimeAnnotationsAttrInfo.java
index 17a48b7..955bf76 100644
--- a/src/proguard/classfile/attribute/annotation/RuntimeAnnotationsAttrInfo.java
+++ b/src/proguard/classfile/attribute/annotation/RuntimeAnnotationsAttrInfo.java
@@ -1,8 +1,8 @@
-/* $Id: RuntimeAnnotationsAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: RuntimeAnnotationsAttrInfo.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttrInfo.java b/src/proguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttrInfo.java
index 89d755e..e5deeed 100644
--- a/src/proguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttrInfo.java
+++ b/src/proguard/classfile/attribute/annotation/RuntimeInvisibleAnnotationsAttrInfo.java
@@ -1,8 +1,8 @@
-/* $Id: RuntimeInvisibleAnnotationsAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: RuntimeInvisibleAnnotationsAttrInfo.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttrInfo.java b/src/proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttrInfo.java
index 1c5387b..fd3e360 100644
--- a/src/proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttrInfo.java
+++ b/src/proguard/classfile/attribute/annotation/RuntimeInvisibleParameterAnnotationsAttrInfo.java
@@ -1,8 +1,8 @@
-/* $Id: RuntimeInvisibleParameterAnnotationsAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: RuntimeInvisibleParameterAnnotationsAttrInfo.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/annotation/RuntimeParameterAnnotationsAttrInfo.java b/src/proguard/classfile/attribute/annotation/RuntimeParameterAnnotationsAttrInfo.java
index 0c2d191..2ccf809 100644
--- a/src/proguard/classfile/attribute/annotation/RuntimeParameterAnnotationsAttrInfo.java
+++ b/src/proguard/classfile/attribute/annotation/RuntimeParameterAnnotationsAttrInfo.java
@@ -1,8 +1,8 @@
-/* $Id: RuntimeParameterAnnotationsAttrInfo.java,v 1.2 2004/11/20 15:41:24 eric Exp $
+/* $Id: RuntimeParameterAnnotationsAttrInfo.java,v 1.6 2005/06/25 22:04:04 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -32,10 +32,11 @@ import java.io.*;
  */
 public abstract class RuntimeParameterAnnotationsAttrInfo extends AttrInfo
 {
-    private static final int CONSTANT_FIELD_SIZE = 2;
+    private static final int CONSTANT_FIELD_SIZE1 = 1;
+    private static final int CONSTANT_FIELD_SIZE2 = 2;
 
 
-    //public int            u2numberOfParameters;
+    public int            u2numberOfParameters;
     //public int[]          u2numberOfAnnotations;
     public Annotation[][] parameterAnnotations;
 
@@ -50,15 +51,17 @@ public abstract class RuntimeParameterAnnotationsAttrInfo extends AttrInfo
      */
     public void annotationsAccept(ClassFile classFile, AnnotationVisitor annotationVisitor)
     {
-        for (int i = 0; i < parameterAnnotations.length; i++)
+        for (int parameterIndex = 0; parameterIndex < u2numberOfParameters; parameterIndex++)
         {
-            Annotation[] annotations = parameterAnnotations[i];
-            for (int j = 0; j < annotations.length; i++)
+            Annotation[] annotations = parameterAnnotations[parameterIndex];
+            int u2numberOfAnnotations = annotations.length;
+
+            for (int i = 0; i < u2numberOfAnnotations; i++)
             {
                 // We don't need double dispatching here, since there is only one
                 // type of Annotation.
                 //annotationVisitor.visitAnnotation(classFile, methodInfo, i, annotations[j]);
-                annotationVisitor.visitAnnotation(classFile, annotations[j]);
+                annotationVisitor.visitAnnotation(classFile, annotations[i]);
             }
         }
     }
@@ -68,16 +71,18 @@ public abstract class RuntimeParameterAnnotationsAttrInfo extends AttrInfo
 
     protected int getLength()
     {
-        int length = CONSTANT_FIELD_SIZE;
+        int length = CONSTANT_FIELD_SIZE1;
 
-        for (int i = 0; i < parameterAnnotations.length; i++)
+        for (int parameterIndex = 0; parameterIndex < u2numberOfParameters; parameterIndex++)
         {
-            length += CONSTANT_FIELD_SIZE;
+            Annotation[] annotations = parameterAnnotations[parameterIndex];
+            int u2numberOfAnnotations = annotations.length;
+
+            length += CONSTANT_FIELD_SIZE2;
 
-            Annotation[] annotations = parameterAnnotations[i];
-            for (int j = 0; j < annotations.length; i++)
+            for (int i = 0; i < u2numberOfAnnotations; i++)
             {
-                length += annotations[j].getLength();
+                length += annotations[i].getLength();
             }
         }
 
@@ -86,34 +91,38 @@ public abstract class RuntimeParameterAnnotationsAttrInfo extends AttrInfo
 
     protected void readInfo(DataInput din, ClassFile classFile) throws IOException
     {
-        int u2numberOfParameters = din.readUnsignedShort();
+        u2numberOfParameters = din.readUnsignedByte();
         parameterAnnotations = new Annotation[u2numberOfParameters][];
 
-        for (int i = 0; i < u2numberOfParameters; i++)
+        for (int parameterIndex = 0; parameterIndex < u2numberOfParameters; parameterIndex++)
         {
             int u2numberOfAnnotations = din.readUnsignedShort();
+
             Annotation[] annotations = new Annotation[u2numberOfAnnotations];
 
-            for (int j = 0; j < u2numberOfAnnotations; j++)
+            for (int i = 0; i < u2numberOfAnnotations; i++)
             {
-                annotations[j] = Annotation.create(din);
+                annotations[i] = Annotation.create(din);
             }
 
-            parameterAnnotations[i] = annotations;
+            parameterAnnotations[parameterIndex] = annotations;
         }
     }
 
     protected void writeInfo(DataOutput dout) throws IOException
     {
-        dout.writeShort(parameterAnnotations.length);
-        for (int i = 0; i < parameterAnnotations.length; i++)
+        dout.writeByte(u2numberOfParameters);
+
+        for (int parameterIndex = 0; parameterIndex < u2numberOfParameters; parameterIndex++)
         {
-            Annotation[] annotations = parameterAnnotations[i];
+            Annotation[] annotations = parameterAnnotations[parameterIndex];
+            int u2numberOfAnnotations = annotations.length;
+
+            dout.writeShort(u2numberOfAnnotations);
 
-            dout.writeShort(annotations.length);
-            for (int j = 0; j < annotations.length; i++)
+            for (int i = 0; i < u2numberOfAnnotations; i++)
             {
-                annotations[j].write(dout);
+                annotations[i].write(dout);
             }
         }
     }
diff --git a/src/proguard/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttrInfo.java b/src/proguard/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttrInfo.java
index 9ea8fc8..c315723 100644
--- a/src/proguard/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttrInfo.java
+++ b/src/proguard/classfile/attribute/annotation/RuntimeVisibleAnnotationsAttrInfo.java
@@ -1,8 +1,8 @@
-/* $Id: RuntimeVisibleAnnotationsAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: RuntimeVisibleAnnotationsAttrInfo.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttrInfo.java b/src/proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttrInfo.java
index a1ee4a3..2644f30 100644
--- a/src/proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttrInfo.java
+++ b/src/proguard/classfile/attribute/annotation/RuntimeVisibleParameterAnnotationsAttrInfo.java
@@ -1,8 +1,8 @@
-/* $Id: RuntimeVisibleParameterAnnotationsAttrInfo.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: RuntimeVisibleParameterAnnotationsAttrInfo.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
diff --git a/src/proguard/classfile/editor/ClassFileReferenceFixer.java b/src/proguard/classfile/editor/ClassFileReferenceFixer.java
new file mode 100644
index 0000000..73df5e5
--- /dev/null
+++ b/src/proguard/classfile/editor/ClassFileReferenceFixer.java
@@ -0,0 +1,495 @@
+/* $Id: ClassFileReferenceFixer.java,v 1.4 2005/06/25 22:07:51 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.editor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This ClassFileVisitor fixes constant pool references to classes whose
+ * names have changed. Descriptors of member references are not updated yet.
+ *
+ * @see MemberReferenceFixer
+ * @author Eric Lafortune
+ */
+public class ClassFileReferenceFixer
+  implements ClassFileVisitor,
+             CpInfoVisitor,
+             MemberInfoVisitor,
+             AttrInfoVisitor,
+             LocalVariableInfoVisitor,
+             LocalVariableTypeInfoVisitor,
+             AnnotationVisitor,
+             ElementValueVisitor
+{
+    private ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor();
+
+
+    // Implementations for ClassFileVisitor.
+
+    public void visitProgramClassFile(ProgramClassFile programClassFile)
+    {
+        // Fix the constant pool.
+        programClassFile.constantPoolEntriesAccept(this);
+
+        // Fix class members.
+        programClassFile.fieldsAccept(this);
+        programClassFile.methodsAccept(this);
+
+        // Fix the attributes.
+        programClassFile.attributesAccept(this);
+    }
+
+
+    public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+    {
+        // Fix class members.
+        libraryClassFile.fieldsAccept(this);
+        libraryClassFile.methodsAccept(this);
+    }
+
+
+    // Implementations for MemberInfoVisitor.
+
+    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+    {
+        // Has the descriptor changed?
+        String descriptor    = programFieldInfo.getDescriptor(programClassFile);
+        String newDescriptor = newDescriptor(descriptor,
+                                             programFieldInfo.referencedClassFile);
+
+        if (!descriptor.equals(newDescriptor))
+        {
+            // Update the descriptor.
+            programFieldInfo.u2descriptorIndex =
+                constantPoolEditor.addUtf8CpInfo(programClassFile, newDescriptor);
+        }
+
+        // Fix the attributes.
+        programFieldInfo.attributesAccept(programClassFile, this);
+    }
+
+
+    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+    {
+        // Has the descriptor changed?
+        String descriptor    = programMethodInfo.getDescriptor(programClassFile);
+        String newDescriptor = newDescriptor(descriptor,
+                                             programMethodInfo.referencedClassFiles);
+
+        if (!descriptor.equals(newDescriptor))
+        {
+            // Update the descriptor.
+            programMethodInfo.u2descriptorIndex =
+                constantPoolEditor.addUtf8CpInfo(programClassFile, newDescriptor);
+        }
+
+        // Fix the attributes.
+        programMethodInfo.attributesAccept(programClassFile, this);
+    }
+
+
+    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+    {
+        // Has the descriptor changed?
+        String descriptor    = libraryFieldInfo.getDescriptor(libraryClassFile);
+        String newDescriptor = newDescriptor(descriptor,
+                                             libraryFieldInfo.referencedClassFile);
+
+        // Update the descriptor.
+        libraryFieldInfo.descriptor = newDescriptor;
+    }
+
+
+    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+    {
+        // Has the descriptor changed?
+        String descriptor    = libraryMethodInfo.getDescriptor(libraryClassFile);
+        String newDescriptor = newDescriptor(descriptor,
+                                             libraryMethodInfo.referencedClassFiles);
+
+        // Update the descriptor.
+        libraryMethodInfo.descriptor = newDescriptor;
+    }
+
+
+    // Implementations for CpInfoVisitor.
+
+    public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+    public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+    public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+    public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+    public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
+    public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
+    public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo) {}
+    public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+    public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+
+
+    public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
+    {
+        // Does the string refer to a class file, due to a Class.forName construct?
+        ClassFile referencedClassFile = stringCpInfo.referencedClassFile;
+        if (referencedClassFile != null)
+        {
+            // Reconstruct the new class name.
+            String externalClassName    = stringCpInfo.getString(classFile);
+            String internalClassName    = ClassUtil.internalClassName(externalClassName);
+            String newInternalClassName = newClassName(internalClassName,
+                                                       referencedClassFile);
+
+            // Update the String entry if required.
+            if (!newInternalClassName.equals(internalClassName))
+            {
+                String newExternalClassName = ClassUtil.externalClassName(newInternalClassName);
+
+                // Refer to a new Utf8 entry.
+                stringCpInfo.u2stringIndex =
+                    constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
+                                                     newExternalClassName);
+            }
+        }
+    }
+
+
+    public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+    {
+        // Do we know the referenced class file?
+        ClassFile referencedClassFile = classCpInfo.referencedClassFile;
+        if (referencedClassFile != null)
+        {
+            // Has the class name changed?
+            String className    = classCpInfo.getName(classFile);
+            String newClassName = newClassName(className, referencedClassFile);
+            if (!className.equals(newClassName))
+            {
+                // Refer to a new Utf8 entry.
+                classCpInfo.u2nameIndex =
+                    constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
+                                                     newClassName);
+            }
+        }
+    }
+
+
+    // Implementations for AttrInfoVisitor.
+
+    public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+    public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+    public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
+    public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+    public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+    public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+    public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+    public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+    public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+    public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+
+
+    public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+    {
+        // Fix the attributes.
+        codeAttrInfo.attributesAccept(classFile, methodInfo, this);
+    }
+
+
+    public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo)
+    {
+        // Fix the types of the local variables.
+        localVariableTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
+    }
+
+
+    public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo)
+    {
+        // Fix the signatures of the local variables.
+        localVariableTypeTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
+    }
+
+
+    public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo)
+    {
+        // Compute the new signature.
+        String signature    = classFile.getCpString(signatureAttrInfo.u2signatureIndex);
+        String newSignature = newDescriptor(signature,
+                                            signatureAttrInfo.referencedClassFiles);
+
+        if (!signature.equals(newSignature))
+        {
+            signatureAttrInfo.u2signatureIndex =
+                constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
+                                                 newSignature);
+        }
+    }
+
+
+    public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo)
+    {
+        // Fix the annotations.
+        runtimeVisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+    }
+
+
+    public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo)
+    {
+        // Fix the annotations.
+        runtimeInvisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+    }
+
+
+    public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo)
+    {
+        // Fix the annotations.
+        runtimeVisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+    }
+
+
+    public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo)
+    {
+        // Fix the annotations.
+        runtimeInvisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+    }
+
+
+    public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo)
+    {
+        // Fix the annotation.
+        annotationDefaultAttrInfo.defaultValueAccept(classFile, this);
+    }
+
+
+    // Implementations for LocalVariableInfoVisitor.
+
+    public void visitLocalVariableInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableInfo localVariableInfo)
+    {
+        // Has the descriptor changed?
+        String descriptor    = classFile.getCpString(localVariableInfo.u2descriptorIndex);
+        String newDescriptor = newDescriptor(descriptor,
+                                             localVariableInfo.referencedClassFile);
+
+        if (!descriptor.equals(newDescriptor))
+        {
+            // Refer to a new Utf8 entry.
+            localVariableInfo.u2descriptorIndex =
+                constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
+                                                 newDescriptor);
+        }
+    }
+
+
+    // Implementations for LocalVariableTypeInfoVisitor.
+
+    public void visitLocalVariableTypeInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeInfo localVariableTypeInfo)
+    {
+        // Has the signature changed?
+        String signature    = classFile.getCpString(localVariableTypeInfo.u2signatureIndex);
+        String newSignature = newDescriptor(signature,
+                                            localVariableTypeInfo.referencedClassFiles);
+
+        if (!signature.equals(newSignature))
+        {
+            localVariableTypeInfo.u2signatureIndex =
+                constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
+                                                 newSignature);
+        }
+    }
+
+
+    // Implementations for AnnotationVisitor.
+
+    public void visitAnnotation(ClassFile classFile, Annotation annotation)
+    {
+        // Compute the new type name.
+        String typeName    = classFile.getCpString(annotation.u2typeIndex);
+        String newTypeName = newDescriptor(typeName,
+                                           annotation.referencedClassFiles);
+
+        if (!typeName.equals(newTypeName))
+        {
+            // Refer to a new Utf8 entry.
+            annotation.u2typeIndex =
+                constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
+                                                 newTypeName);
+        }
+
+        // Fix the element values.
+        annotation.elementValuesAccept(classFile, this);
+    }
+
+
+    // Implementations for ElementValueVisitor.
+
+    public void visitConstantElementValue(ClassFile classFile, Annotation annotation, ConstantElementValue constantElementValue)
+    {
+    }
+
+
+    public void visitEnumConstantElementValue(ClassFile classFile, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
+    {
+        // Compute the new type name.
+        String typeName    = classFile.getCpString(enumConstantElementValue.u2typeNameIndex);
+        String newTypeName = newDescriptor(typeName,
+                                           enumConstantElementValue.referencedClassFiles);
+
+        if (!typeName.equals(newTypeName))
+        {
+            // Refer to a new Utf8 entry.
+            enumConstantElementValue.u2typeNameIndex =
+                constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
+                                                 newTypeName);
+        }
+    }
+
+
+    public void visitClassElementValue(ClassFile classFile, Annotation annotation, ClassElementValue classElementValue)
+    {
+        // Compute the new class name.
+        String className    = classFile.getCpString(classElementValue.u2classInfoIndex);
+        String newClassName = newDescriptor(className,
+                                            classElementValue.referencedClassFiles);
+
+        if (!className.equals(newClassName))
+        {
+            // Refer to a new Utf8 entry.
+            classElementValue.u2classInfoIndex =
+                constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
+                                                 newClassName);
+        }
+    }
+
+
+    public void visitAnnotationElementValue(ClassFile classFile, Annotation annotation, AnnotationElementValue annotationElementValue)
+    {
+        // Fix the annotation.
+        annotationElementValue.annotationAccept(classFile, this);
+    }
+
+
+    public void visitArrayElementValue(ClassFile classFile, Annotation annotation, ArrayElementValue arrayElementValue)
+    {
+        // Fix the element values.
+        arrayElementValue.elementValuesAccept(classFile, annotation, this);
+    }
+
+
+    // Small utility methods.
+
+    private static String newDescriptor(String    descriptor,
+                                        ClassFile referencedClassFile)
+    {
+        // If there is no referenced class, the descriptor won't change.
+        if (referencedClassFile == null)
+        {
+            return descriptor;
+        }
+
+        // Unravel and reconstruct the class element of the descriptor.
+        DescriptorClassEnumeration descriptorClassEnumeration =
+            new DescriptorClassEnumeration(descriptor);
+
+        StringBuffer newDescriptorBuffer = new StringBuffer(descriptor.length());
+        newDescriptorBuffer.append(descriptorClassEnumeration.nextFluff());
+
+        // Only if the descriptor contains a class name (e.g. with an array of
+        // primitive types), the descriptor can change.
+        if (descriptorClassEnumeration.hasMoreClassNames())
+        {
+            String className = descriptorClassEnumeration.nextClassName();
+            String fluff     = descriptorClassEnumeration.nextFluff();
+
+            String newClassName = newClassName(className,
+                                               referencedClassFile);
+
+            newDescriptorBuffer.append(newClassName);
+            newDescriptorBuffer.append(fluff);
+        }
+
+        return newDescriptorBuffer.toString();
+    }
+
+
+    private static String newDescriptor(String      descriptor,
+                                        ClassFile[] referencedClassFiles)
+    {
+        // If there are no referenced classes, the descriptor won't change.
+        if (referencedClassFiles == null ||
+            referencedClassFiles.length == 0)
+        {
+            return descriptor;
+        }
+
+        // Unravel and reconstruct the class elements of the descriptor.
+        DescriptorClassEnumeration descriptorClassEnumeration =
+            new DescriptorClassEnumeration(descriptor);
+
+        StringBuffer newDescriptorBuffer = new StringBuffer(descriptor.length());
+        newDescriptorBuffer.append(descriptorClassEnumeration.nextFluff());
+
+        int index = 0;
+        while (descriptorClassEnumeration.hasMoreClassNames())
+        {
+            String className = descriptorClassEnumeration.nextClassName();
+            String fluff     = descriptorClassEnumeration.nextFluff();
+
+            String newClassName = newClassName(className,
+                                               referencedClassFiles[index++]);
+
+            newDescriptorBuffer.append(newClassName);
+            newDescriptorBuffer.append(fluff);
+        }
+
+        return newDescriptorBuffer.toString();
+    }
+
+
+    /**
+     * Returns the new class name based on the given class name and the new
+     * name of the given referenced class file. Class names of array types
+     * are handled properly.
+     */
+    private static String newClassName(String    className,
+                                       ClassFile referencedClassFile)
+    {
+        // If there is no referenced class, the class name won't change.
+        if (referencedClassFile == null)
+        {
+            return className;
+        }
+
+        // Reconstruct the class name.
+        String newClassName = referencedClassFile.getName();
+
+        // Is it an array type?
+        if (className.charAt(0) == ClassConstants.INTERNAL_TYPE_ARRAY)
+        {
+            // Add the array prefixes and suffix "[L...;".
+            newClassName =
+                 className.substring(0, className.indexOf(ClassConstants.INTERNAL_TYPE_CLASS_START)+1) +
+                 newClassName +
+                 ClassConstants.INTERNAL_TYPE_CLASS_END;
+        }
+
+        return newClassName;
+    }
+}
diff --git a/src/proguard/classfile/editor/CodeAttrInfoEditor.java b/src/proguard/classfile/editor/CodeAttrInfoEditor.java
index c882cb9..5f78a41 100644
--- a/src/proguard/classfile/editor/CodeAttrInfoEditor.java
+++ b/src/proguard/classfile/editor/CodeAttrInfoEditor.java
@@ -1,8 +1,8 @@
-/* $Id: CodeAttrInfoEditor.java,v 1.9 2004/10/10 20:56:58 eric Exp $
+/* $Id: CodeAttrInfoEditor.java,v 1.13 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -42,7 +42,10 @@ public class CodeAttrInfoEditor
 {
     private int              codeLength;
     private boolean          modified;
+    private boolean          inserted;
+
     /*private*/public Instruction[]    preInsertions;
+    /*private*/public Instruction[]    replacements;
     /*private*/public Instruction[]    postInsertions;
     private boolean[]        deleted;
 
@@ -61,6 +64,7 @@ public class CodeAttrInfoEditor
         this.codeLength = codeLength;
 
         preInsertions    = new Instruction[codeLength];
+        replacements     = new Instruction[codeLength];
         postInsertions   = new Instruction[codeLength];
         deleted          = new boolean[codeLength];
 
@@ -80,6 +84,7 @@ public class CodeAttrInfoEditor
         if (preInsertions.length < codeLength)
         {
             preInsertions  = new Instruction[codeLength];
+            replacements   = new Instruction[codeLength];
             postInsertions = new Instruction[codeLength];
             deleted        = new boolean[codeLength];
         }
@@ -88,25 +93,35 @@ public class CodeAttrInfoEditor
             for (int index = 0; index < codeLength; index++)
             {
                 preInsertions[index]  = null;
+                replacements[index]   = null;
                 postInsertions[index] = null;
                 deleted[index]        = false;
             }
         }
 
         modified = false;
+        inserted = false;
     }
 
 
     /**
-     * Remembers to replace the instruction at the given offset by the given
-     * instruction.
-     * @param instructionOffset the offset of the instruction to be replaced.
+     * Remembers to place the given instruction right before the instruction
+     * at the given offset.
+     * @param instructionOffset the offset of the instruction.
      * @param instruction       the new instruction.
      */
-    public void replaceInstruction(int instructionOffset, Instruction instruction)
+    public void insertBeforeInstruction(int instructionOffset, Instruction instruction)
     {
-        deleteInstruction(instructionOffset);
-        insertBeforeInstruction(instructionOffset, instruction);
+        if (instructionOffset < 0 ||
+            instructionOffset >= codeLength)
+        {
+            throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
+        }
+
+        preInsertions[instructionOffset] = instruction;
+
+        modified = true;
+        inserted = true;
     }
 
 
@@ -116,20 +131,7 @@ public class CodeAttrInfoEditor
      * @param instructionOffset the offset of the instruction to be replaced.
      * @param instruction       the new instruction.
      */
-    public void replaceInstruction2(int instructionOffset, Instruction instruction)
-    {
-        deleteInstruction(instructionOffset);
-        insertAfterInstruction(instructionOffset, instruction);
-    }
-
-
-    /**
-     * Remembers to place the given instruction right before the instruction
-     * at the given offset.
-     * @param instructionOffset the offset of the instruction.
-     * @param instruction       the new instruction.
-     */
-    public void insertBeforeInstruction(int instructionOffset, Instruction instruction)
+    public void replaceInstruction(int instructionOffset, Instruction instruction)
     {
         if (instructionOffset < 0 ||
             instructionOffset >= codeLength)
@@ -137,7 +139,7 @@ public class CodeAttrInfoEditor
             throw new IllegalArgumentException("Invalid instruction offset ["+instructionOffset+"] in code with length ["+codeLength+"]");
         }
 
-        preInsertions[instructionOffset] = instruction;
+        replacements[instructionOffset] = instruction;
 
         modified = true;
     }
@@ -160,6 +162,7 @@ public class CodeAttrInfoEditor
         postInsertions[instructionOffset] = instruction;
 
         modified = true;
+        inserted = true;
     }
 
 
@@ -178,6 +181,7 @@ public class CodeAttrInfoEditor
         deleted[instructionOffset] = true;
 
         modified = true;
+        inserted = true;
     }
 
 
@@ -188,6 +192,7 @@ public class CodeAttrInfoEditor
     public boolean isModified(int instructionOffset)
     {
         return preInsertions[instructionOffset]  != null ||
+               replacements[instructionOffset]   != null ||
                postInsertions[instructionOffset] != null ||
                deleted[instructionOffset];
 
@@ -230,22 +235,31 @@ public class CodeAttrInfoEditor
             return;
         }
 
-        // Move and remap the instructions.
-        codeAttrInfo.u4codeLength =
-            moveInstructions(classFile, methodInfo, codeAttrInfo);
+        // Check if we can perform a faster simple replacement of instructions.
+        if (canPerformSimpleReplacements(codeAttrInfo))
+        {
+            // Simply overwrite the instructions.
+            performSimpleReplacements(codeAttrInfo);
+        }
+        else
+        {
+            // Move and remap the instructions.
+            codeAttrInfo.u4codeLength =
+                moveInstructions(classFile, methodInfo, codeAttrInfo);
 
-        // Remap the exception table.
-        codeAttrInfo.exceptionsAccept(classFile, methodInfo, this);
+            // Remap the exception table.
+            codeAttrInfo.exceptionsAccept(classFile, methodInfo, this);
 
-        // Remap  the line number table and the local variable table.
-        codeAttrInfo.attributesAccept(classFile, methodInfo, this);
+            // Remap  the line number table and the local variable table.
+            codeAttrInfo.attributesAccept(classFile, methodInfo, this);
 
-        // Remove exceptions with empty code blocks.
-        codeAttrInfo.u2exceptionTableLength =
-             removeEmptyExceptions(codeAttrInfo.exceptionTable,
-                                   codeAttrInfo.u2exceptionTableLength);
+            // Remove exceptions with empty code blocks.
+            codeAttrInfo.u2exceptionTableLength =
+                 removeEmptyExceptions(codeAttrInfo.exceptionTable,
+                                       codeAttrInfo.u2exceptionTableLength);
+        }
 
-        // Update maximum stack size.
+        // Update the maximum stack size.
         stackSizeUpdater.visitCodeAttrInfo(classFile, methodInfo, codeAttrInfo);
     }
 
@@ -381,6 +395,65 @@ public class CodeAttrInfoEditor
     // Small utility methods.
 
     /**
+     * Checks if it is possible to modifies the given code without having to
+     * update any offsets.
+     *
+     * @param codeAttrInfo the code to be changed.
+     * @return the new code length.
+     */
+    private boolean canPerformSimpleReplacements(CodeAttrInfo codeAttrInfo)
+    {
+        if (inserted)
+        {
+            return false;
+        }
+
+        byte[] code       = codeAttrInfo.code;
+        int    codeLength = codeAttrInfo.u4codeLength;
+
+        // Go over all replacement instructions.
+        for (int offset = 0; offset < codeLength; offset++)
+        {
+            // Check if the replacement instruction, if any, has a different
+            // length than the original instruction.
+            Instruction replacementInstruction = replacements[offset];
+            if (replacementInstruction != null &&
+                replacementInstruction.length(offset) !=
+                    InstructionFactory.create(code, offset).length(offset))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Modifies the given code without updating any offsets.
+     *
+     * @param codeAttrInfo the code to be changed.
+     */
+    private void performSimpleReplacements(CodeAttrInfo codeAttrInfo)
+    {
+        byte[] code       = codeAttrInfo.code;
+        int    codeLength = codeAttrInfo.u4codeLength;
+
+        // Go over all replacement instructions.
+        for (int offset = 0; offset < codeLength; offset++)
+        {
+            // Overwrite the original instruction with the replacement
+            // instruction if any.
+            Instruction replacementInstruction = replacements[offset];
+            if (replacementInstruction != null)
+            {
+                replacementInstruction.write(codeAttrInfo, offset);
+            }
+        }
+    }
+
+
+    /**
      * Modifies the given code based on the previously specified changes.
      *
      * @param classFile    the class file of the code to be changed.
@@ -475,8 +548,14 @@ public class CodeAttrInfoEditor
             newOffset += preInstruction.length(newOffset);
         }
 
-        // Account for the current instruction, if it shouldn't be deleted.
-        if (!deleted[oldOffset] )
+        // Account for the replacement instruction, or for the current
+        // instruction, if it shouldn't be  deleted.
+        Instruction replacementInstruction = replacements[oldOffset];
+        if (replacementInstruction != null)
+        {
+            newOffset += replacementInstruction.length(newOffset);
+        }
+        else if (!deleted[oldOffset])
         {
             // Note that the instruction's length may change at its new offset,
             // e.g. if it is a switch instruction.
@@ -516,8 +595,18 @@ public class CodeAttrInfoEditor
             newOffset += preInstruction.length(newOffset);
         }
 
-        // Remap and insert the current instruction, if it shouldn't be deleted.
-        if (!deleted[oldOffset])
+        // Remap and insert the replacment instruction, or the current
+        // instruction, if it shouldn't be deleted.
+        Instruction replacementInstruction = replacements[oldOffset];
+        if (replacementInstruction != null)
+        {
+            replacementInstruction.accept(classFile, methodInfo, codeAttrInfo, oldOffset, this);
+
+            replacementInstruction.write(codeAttrInfo, newOffset);
+
+            newOffset += replacementInstruction.length(newOffset);
+        }
+        else if (!deleted[oldOffset])
         {
             instruction.accept(classFile, methodInfo, codeAttrInfo, oldOffset, this);
 
diff --git a/src/proguard/classfile/editor/CodeAttrInfoEditorResetter.java b/src/proguard/classfile/editor/CodeAttrInfoEditorResetter.java
index 6e0b678..147b54a 100644
--- a/src/proguard/classfile/editor/CodeAttrInfoEditorResetter.java
+++ b/src/proguard/classfile/editor/CodeAttrInfoEditorResetter.java
@@ -1,8 +1,8 @@
-/* $Id: CodeAttrInfoEditorResetter.java,v 1.3 2004/10/10 20:56:58 eric Exp $
+/* $Id: CodeAttrInfoEditorResetter.java,v 1.4 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/ComparableCpInfo.java b/src/proguard/classfile/editor/ComparableCpInfo.java
index 3b7c539..8f6ac86 100644
--- a/src/proguard/classfile/editor/ComparableCpInfo.java
+++ b/src/proguard/classfile/editor/ComparableCpInfo.java
@@ -1,8 +1,8 @@
-/* $Id: ComparableCpInfo.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+/* $Id: ComparableCpInfo.java,v 1.5 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/ConstantPoolEditor.java b/src/proguard/classfile/editor/ConstantPoolEditor.java
index ec99ae2..a0d5725 100644
--- a/src/proguard/classfile/editor/ConstantPoolEditor.java
+++ b/src/proguard/classfile/editor/ConstantPoolEditor.java
@@ -1,8 +1,8 @@
-/* $Id: ConstantPoolEditor.java,v 1.7 2004/11/20 15:41:24 eric Exp $
+/* $Id: ConstantPoolEditor.java,v 1.10 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -29,6 +29,9 @@ import proguard.classfile.*;
  */
 public class ConstantPoolEditor
 {
+    private static final boolean DEBUG = false;
+
+
     /**
      * Finds or creates a StringCpInfo constant pool entry with the given value,
      * in the given class file.
@@ -66,6 +69,24 @@ public class ConstantPoolEditor
 
 
     /**
+     * Finds or creates a FieldrefCpInfo constant pool entry for the given
+     * class and field, in the given class file.
+     * @return the constant pool index of the FieldrefCpInfo.
+     */
+    public int addFieldrefCpInfo(ProgramClassFile programClassFile,
+                                 ClassFile        referencedClassFile,
+                                 MemberInfo       referencedMemberInfo)
+    {
+        return addFieldrefCpInfo(programClassFile,
+                                 referencedClassFile.getName(),
+                                 referencedMemberInfo.getName(referencedClassFile),
+                                 referencedMemberInfo.getDescriptor(referencedClassFile),
+                                 referencedClassFile,
+                                 referencedMemberInfo);
+    }
+
+
+    /**
      * Finds or creates a FieldrefCpInfo constant pool entry with the given
      * class name, field name, and descriptor, in the given class file.
      * @return the constant pool index of the FieldrefCpInfo.
@@ -75,15 +96,13 @@ public class ConstantPoolEditor
                                  String           name,
                                  String           descriptor,
                                  ClassFile        referencedClassFile,
-                                 MemberInfo       referencedMemberInfo,
-                                 ClassFile[]      referencedClassFiles)
+                                 MemberInfo       referencedMemberInfo)
     {
         return addFieldrefCpInfo(programClassFile,
                                  className,
                                  addNameAndTypeCpInfo(programClassFile,
                                                       name,
-                                                      descriptor,
-                                                      referencedClassFiles),
+                                                      descriptor),
                                  referencedClassFile,
                                  referencedMemberInfo);
     }
@@ -121,15 +140,13 @@ public class ConstantPoolEditor
                                  String           name,
                                  String           descriptor,
                                  ClassFile        referencedClassFile,
-                                 MemberInfo       referencedMemberInfo,
-                                 ClassFile[]      referencedClassFiles)
+                                 MemberInfo       referencedMemberInfo)
     {
         return addFieldrefCpInfo(programClassFile,
                                  classIndex,
                                  addNameAndTypeCpInfo(programClassFile,
                                                       name,
-                                                      descriptor,
-                                                      referencedClassFiles),
+                                                      descriptor),
                                  referencedClassFile,
                                  referencedMemberInfo);
     }
@@ -176,6 +193,148 @@ public class ConstantPoolEditor
 
 
     /**
+     * Finds or creates a InterfaceMethodrefCpInfo constant pool entry with the
+     * given class name, method name, and descriptor, in the given class file.
+     * @return the constant pool index of the InterfaceMethodrefCpInfo.
+     */
+    public int addInterfaceMethodrefCpInfo(ProgramClassFile programClassFile,
+                                           String           className,
+                                           String           name,
+                                           String           descriptor,
+                                           ClassFile        referencedClassFile,
+                                           MemberInfo       referencedMemberInfo)
+    {
+        return addInterfaceMethodrefCpInfo(programClassFile,
+                                           className,
+                                           addNameAndTypeCpInfo(programClassFile,
+                                                                name,
+                                                                descriptor),
+                                                                referencedClassFile,
+                                                                referencedMemberInfo);
+    }
+
+
+    /**
+     * Finds or creates a InterfaceMethodrefCpInfo constant pool entry with the
+     * given class name, method name, and descriptor, in the given class file.
+     * @return the constant pool index of the InterfaceMethodrefCpInfo.
+     */
+    public int addInterfaceMethodrefCpInfo(ProgramClassFile programClassFile,
+                                           String           className,
+                                           int              nameAndTypeIndex,
+                                           ClassFile        referencedClassFile,
+                                           MemberInfo       referencedMemberInfo)
+    {
+        return addInterfaceMethodrefCpInfo(programClassFile,
+                                           addClassCpInfo(programClassFile,
+                                                          className,
+                                                          referencedClassFile),
+                                                          nameAndTypeIndex,
+                                                          referencedClassFile,
+                                                          referencedMemberInfo);
+    }
+
+
+    /**
+     * Finds or creates a InterfaceMethodrefCpInfo constant pool entry for the
+     * given class and method, in the given class file.
+     * @return the constant pool index of the InterfaceMethodrefCpInfo.
+     */
+    public int addInterfaceMethodrefCpInfo(ProgramClassFile programClassFile,
+                                           ClassFile        referencedClassFile,
+                                           MemberInfo       referencedMemberInfo)
+    {
+        return addInterfaceMethodrefCpInfo(programClassFile,
+                                           referencedClassFile.getName(),
+                                           referencedMemberInfo.getName(referencedClassFile),
+                                           referencedMemberInfo.getDescriptor(referencedClassFile),
+                                           referencedClassFile,
+                                           referencedMemberInfo);
+    }
+
+
+    /**
+     * Finds or creates a InterfaceMethodrefCpInfo constant pool entry with the
+     * given class constant pool entry index, method name, and descriptor, in
+     * the given class file.
+     * @return the constant pool index of the InterfaceMethodrefCpInfo.
+     */
+    public int addInterfaceMethodrefCpInfo(ProgramClassFile programClassFile,
+                                           int              classIndex,
+                                           String           name,
+                                           String           descriptor,
+                                           ClassFile        referencedClassFile,
+                                           MemberInfo       referencedMemberInfo)
+    {
+        return addInterfaceMethodrefCpInfo(programClassFile,
+                                           classIndex,
+                                           addNameAndTypeCpInfo(programClassFile,
+                                                                name,
+                                                                descriptor),
+                                           referencedClassFile,
+                                           referencedMemberInfo);
+    }
+
+
+    /**
+     * Finds or creates a InterfaceMethodrefCpInfo constant pool entry with the
+     * given class constant pool entry index and name and type constant pool
+     * entry index the given class file.
+     * @return the constant pool index of the InterfaceMethodrefCpInfo.
+     */
+    public int addInterfaceMethodrefCpInfo(ProgramClassFile programClassFile,
+                                           int              classIndex,
+                                           int              nameAndTypeIndex,
+                                           ClassFile        referencedClassFile,
+                                           MemberInfo       referencedMemberInfo)
+    {
+        CpInfo[] constantPool      = programClassFile.constantPool;
+        int      constantPoolCount = programClassFile.u2constantPoolCount;
+
+        // Check if the entry already exists.
+        for (int index = 1; index < constantPoolCount; index++)
+        {
+            CpInfo cpInfo = constantPool[index];
+
+            if (cpInfo != null &&
+                            cpInfo.getTag() == ClassConstants.CONSTANT_InterfaceMethodref)
+            {
+                InterfaceMethodrefCpInfo methodrefCpInfo = (InterfaceMethodrefCpInfo)cpInfo;
+                if (methodrefCpInfo.u2classIndex       == classIndex &&
+                                methodrefCpInfo.u2nameAndTypeIndex == nameAndTypeIndex)
+                {
+                    return index;
+                }
+            }
+        }
+
+        return addCpInfo(programClassFile,
+                         new InterfaceMethodrefCpInfo(classIndex,
+                                                      nameAndTypeIndex,
+                                                      referencedClassFile,
+                                                      referencedMemberInfo));
+    }
+
+
+    /**
+     * Finds or creates a MethodrefCpInfo constant pool entry for the given
+     * class and method, in the given class file.
+     * @return the constant pool index of the MethodrefCpInfo.
+     */
+    public int addMethodrefCpInfo(ProgramClassFile programClassFile,
+                                  ClassFile        referencedClassFile,
+                                  MemberInfo       referencedMemberInfo)
+    {
+        return addMethodrefCpInfo(programClassFile,
+                                  referencedClassFile.getName(),
+                                  referencedMemberInfo.getName(referencedClassFile),
+                                  referencedMemberInfo.getDescriptor(referencedClassFile),
+                                  referencedClassFile,
+                                  referencedMemberInfo);
+    }
+
+
+    /**
      * Finds or creates a MethodrefCpInfo constant pool entry with the given
      * class name, method name, and descriptor, in the given class file.
      * @return the constant pool index of the MethodrefCpInfo.
@@ -185,15 +344,13 @@ public class ConstantPoolEditor
                                   String           name,
                                   String           descriptor,
                                   ClassFile        referencedClassFile,
-                                  MemberInfo       referencedMemberInfo,
-                                  ClassFile[]      referencedClassFiles)
+                                  MemberInfo       referencedMemberInfo)
     {
         return addMethodrefCpInfo(programClassFile,
                                   className,
                                   addNameAndTypeCpInfo(programClassFile,
                                                        name,
-                                                       descriptor,
-                                                       referencedClassFiles),
+                                                       descriptor),
                                   referencedClassFile,
                                   referencedMemberInfo);
     }
@@ -231,15 +388,13 @@ public class ConstantPoolEditor
                                   String           name,
                                   String           descriptor,
                                   ClassFile        referencedClassFile,
-                                  MemberInfo       referencedMemberInfo,
-                                  ClassFile[]      referencedClassFiles)
+                                  MemberInfo       referencedMemberInfo)
     {
         return addMethodrefCpInfo(programClassFile,
                                   classIndex,
                                   addNameAndTypeCpInfo(programClassFile,
                                                        name,
-                                                       descriptor,
-                                                       referencedClassFiles),
+                                                       descriptor),
                                   referencedClassFile,
                                   referencedMemberInfo);
     }
@@ -286,112 +441,16 @@ public class ConstantPoolEditor
 
 
     /**
-     * Finds or creates a InterfaceMethodrefCpInfo constant pool entry with the
-     * given class name, method name, and descriptor, in the given class file.
-     * @return the constant pool index of the InterfaceMethodrefCpInfo.
-     */
-    public int addInterfaceMethodrefCpInfo(ProgramClassFile programClassFile,
-                                           String           className,
-                                           String           name,
-                                           String           descriptor,
-                                           ClassFile        referencedClassFile,
-                                           MemberInfo       referencedMemberInfo,
-                                           ClassFile[]      referencedClassFiles)
-    {
-        return addInterfaceMethodrefCpInfo(programClassFile,
-                                           className,
-                                           addNameAndTypeCpInfo(programClassFile,
-                                                                name,
-                                                                descriptor,
-                                                                referencedClassFiles),
-                                                                referencedClassFile,
-                                                                referencedMemberInfo);
-    }
-
-
-    /**
-     * Finds or creates a InterfaceMethodrefCpInfo constant pool entry with the
-     * given class name, method name, and descriptor, in the given class file.
-     * @return the constant pool index of the InterfaceMethodrefCpInfo.
-     */
-    public int addInterfaceMethodrefCpInfo(ProgramClassFile programClassFile,
-                                           String           className,
-                                           int              nameAndTypeIndex,
-                                           ClassFile        referencedClassFile,
-                                           MemberInfo       referencedMemberInfo)
-    {
-        return addInterfaceMethodrefCpInfo(programClassFile,
-                                           addClassCpInfo(programClassFile,
-                                                          className,
-                                                          referencedClassFile),
-                                                          nameAndTypeIndex,
-                                                          referencedClassFile,
-                                                          referencedMemberInfo);
-    }
-
-
-    /**
-     * Finds or creates a InterfaceMethodrefCpInfo constant pool entry with the
-     * given class constant pool entry index, method name, and descriptor, in
-     * the given class file.
-     * @return the constant pool index of the InterfaceMethodrefCpInfo.
-     */
-    public int addInterfaceMethodrefCpInfo(ProgramClassFile programClassFile,
-                                           int              classIndex,
-                                           String           name,
-                                           String           descriptor,
-                                           ClassFile        referencedClassFile,
-                                           MemberInfo       referencedMemberInfo,
-                                           ClassFile[]      referencedClassFiles)
-    {
-        return addInterfaceMethodrefCpInfo(programClassFile,
-                                           classIndex,
-                                           addNameAndTypeCpInfo(programClassFile,
-                                                                name,
-                                                                descriptor,
-                                                                referencedClassFiles),
-                                                                referencedClassFile,
-                                                                referencedMemberInfo);
-    }
-
-
-    /**
-     * Finds or creates a InterfaceMethodrefCpInfo constant pool entry with the
-     * given class constant pool entry index and name and type constant pool
-     * entry index the given class file.
-     * @return the constant pool index of the InterfaceMethodrefCpInfo.
+     * Finds or creates a ClassCpInfo constant pool entry for the given class,
+     * in the given class file.
+     * @return the constant pool index of the ClassCpInfo.
      */
-    public int addInterfaceMethodrefCpInfo(ProgramClassFile programClassFile,
-                                           int              classIndex,
-                                           int              nameAndTypeIndex,
-                                           ClassFile        referencedClassFile,
-                                           MemberInfo       referencedMemberInfo)
+    public int addClassCpInfo(ProgramClassFile programClassFile,
+                              ClassFile        referencedClassFile)
     {
-        CpInfo[] constantPool      = programClassFile.constantPool;
-        int      constantPoolCount = programClassFile.u2constantPoolCount;
-
-        // Check if the entry already exists.
-        for (int index = 1; index < constantPoolCount; index++)
-        {
-            CpInfo cpInfo = constantPool[index];
-
-            if (cpInfo != null &&
-                            cpInfo.getTag() == ClassConstants.CONSTANT_InterfaceMethodref)
-            {
-                InterfaceMethodrefCpInfo methodrefCpInfo = (InterfaceMethodrefCpInfo)cpInfo;
-                if (methodrefCpInfo.u2classIndex       == classIndex &&
-                                methodrefCpInfo.u2nameAndTypeIndex == nameAndTypeIndex)
-                {
-                    return index;
-                }
-            }
-        }
-
-        return addCpInfo(programClassFile,
-                         new InterfaceMethodrefCpInfo(classIndex,
-                                                      nameAndTypeIndex,
-                                                      referencedClassFile,
-                                                      referencedMemberInfo));
+        return addClassCpInfo(programClassFile,
+                              referencedClassFile.getName(),
+                              referencedClassFile);
     }
 
 
@@ -404,7 +463,7 @@ public class ConstantPoolEditor
                               String           name,
                               ClassFile        referencedClassFile)
     {
-        CpInfo[] constantPool        = programClassFile.constantPool;
+        CpInfo[] constantPool      = programClassFile.constantPool;
         int      constantPoolCount = programClassFile.u2constantPoolCount;
 
         // Check if the entry already exists.
@@ -438,10 +497,9 @@ public class ConstantPoolEditor
      */
     public int addNameAndTypeCpInfo(ProgramClassFile programClassFile,
                                     String           name,
-                                    String           type,
-                                    ClassFile[]      referencedClassFiles)
+                                    String           type)
     {
-        CpInfo[] constantPool        = programClassFile.constantPool;
+        CpInfo[] constantPool      = programClassFile.constantPool;
         int      constantPoolCount = programClassFile.u2constantPoolCount;
 
         // Check if the entry already exists.
@@ -466,20 +524,19 @@ public class ConstantPoolEditor
 
         return addCpInfo(programClassFile,
                          new NameAndTypeCpInfo(nameIndex,
-                                               descriptorIndex,
-                                               referencedClassFiles));
+                                               descriptorIndex));
     }
 
 
     /**
-     * Finds or creates an Utf8CpInfo constant pool entry for the given string,
+     * Finds or creates a Utf8CpInfo constant pool entry for the given string,
      * in the given class file.
      * @return the constant pool index of the Utf8CpInfo.
      */
     public int addUtf8CpInfo(ProgramClassFile programClassFile,
                              String           string)
     {
-        CpInfo[] constantPool        = programClassFile.constantPool;
+        CpInfo[] constantPool      = programClassFile.constantPool;
         int      constantPoolCount = programClassFile.u2constantPoolCount;
 
         // Check if the entry already exists.
@@ -507,10 +564,10 @@ public class ConstantPoolEditor
      * in the given class file.
      * @return the constant pool index for the added entry.
      */
-    private int addCpInfo(ProgramClassFile programClassFile,
-                          CpInfo           cpInfo)
+    public int addCpInfo(ProgramClassFile programClassFile,
+                         CpInfo           cpInfo)
     {
-        CpInfo[] constantPool        = programClassFile.constantPool;
+        CpInfo[] constantPool      = programClassFile.constantPool;
         int      constantPoolCount = programClassFile.u2constantPoolCount;
 
         // Make sure there is enough space for another constant pool entry.
@@ -523,6 +580,11 @@ public class ConstantPoolEditor
             constantPool = programClassFile.constantPool;
         }
 
+        if (DEBUG)
+        {
+            System.out.println(programClassFile.getName()+": adding ["+cpInfo.getClass().getName()+"] at index "+programClassFile.u2constantPoolCount);
+        }
+
         // Create a new Utf8CpInfo for the given string.
         constantPool[programClassFile.u2constantPoolCount++] = cpInfo;
 
diff --git a/src/proguard/classfile/editor/ConstantPoolRemapper.java b/src/proguard/classfile/editor/ConstantPoolRemapper.java
index ef7460f..170f2e1 100644
--- a/src/proguard/classfile/editor/ConstantPoolRemapper.java
+++ b/src/proguard/classfile/editor/ConstantPoolRemapper.java
@@ -1,8 +1,8 @@
-/* $Id: ConstantPoolRemapper.java,v 1.9 2004/11/20 15:41:24 eric Exp $
+/* $Id: ConstantPoolRemapper.java,v 1.11 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -542,28 +542,17 @@ public class ConstantPoolRemapper
 
     public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
     {
-        // Remap the instruction, and get the old and the new instruction length.
-        int oldLength = cpInstruction.length(offset);
-
-        cpInstruction.cpIndex = remapCpIndex(cpInstruction.cpIndex);
-        cpInstruction.shrink();
-
-        int newLength = cpInstruction.length(offset);
-
-        // Is the code length changing?
-        if (newLength != oldLength ||
-            codeAttrInfoEditor.isModified())
+        // Is the new constant pool index different from the original one?
+        int newCpIndex = remapCpIndex(cpInstruction.cpIndex);
+        if (newCpIndex != cpInstruction.cpIndex)
         {
-            // We have to go through the code attribute editor.
+            // Replace the instruction.
             cpInstruction = new CpInstruction().copy(cpInstruction);
+            cpInstruction.cpIndex = newCpIndex;
+            cpInstruction.shrink();
 
             codeAttrInfoEditor.replaceInstruction(offset, cpInstruction);
         }
-        else
-        {
-            // We can write the instruction directly.
-            cpInstruction.write(codeAttrInfo, offset);
-        }
     }
 
 
diff --git a/src/proguard/classfile/editor/ConstantPoolSorter.java b/src/proguard/classfile/editor/ConstantPoolSorter.java
index 9291b5b..107e9ef 100644
--- a/src/proguard/classfile/editor/ConstantPoolSorter.java
+++ b/src/proguard/classfile/editor/ConstantPoolSorter.java
@@ -1,8 +1,8 @@
-/* $Id: ConstantPoolSorter.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+/* $Id: ConstantPoolSorter.java,v 1.6 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/MemberReferenceFixer.java b/src/proguard/classfile/editor/MemberReferenceFixer.java
new file mode 100644
index 0000000..052b83d
--- /dev/null
+++ b/src/proguard/classfile/editor/MemberReferenceFixer.java
@@ -0,0 +1,469 @@
+/* $Id: MemberReferenceFixer.java,v 1.4 2005/06/25 22:07:51 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.editor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This ClassFileVisitor fixes constant pool field and method references to
+ * fields and methods whose names or descriptors have changed.
+ *
+ * @author Eric Lafortune
+ */
+public class MemberReferenceFixer
+implements   ClassFileVisitor,
+             CpInfoVisitor,
+             MemberInfoVisitor,
+             AttrInfoVisitor,
+             AnnotationVisitor,
+             ElementValueVisitor
+{
+    private static final boolean DEBUG = false;
+
+
+    private ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor();
+    private StackSizeUpdater   stackSizeUpdater;
+
+    // Parameter for the visitor methods.
+    private int cpIndex;
+
+    // Return values for the visitor methods.
+    private boolean isInterfaceMethod;
+    private boolean stackSizesMayHaveChanged;
+
+
+    /**
+     * Creates a new MemberReferenceFixer.
+     * @param codeLength an estimate of the maximum length of all the code that
+     *                   will be edited.
+     */
+    public MemberReferenceFixer(int codeLength)
+    {
+        stackSizeUpdater = new StackSizeUpdater(codeLength);
+    }
+
+
+    // Implementations for ClassFileVisitor.
+
+    public void visitProgramClassFile(ProgramClassFile programClassFile)
+    {
+        stackSizesMayHaveChanged = false;
+
+        // Fix the constant pool entries.
+        for (int index = 1; index < programClassFile.u2constantPoolCount; index++)
+        {
+            CpInfo cpInfo = programClassFile.constantPool[index];
+            if (cpInfo != null)
+            {
+                // Fix the entry, replacing it entirely if needed.
+                this.cpIndex = index;
+
+                cpInfo.accept(programClassFile, this);
+            }
+        }
+
+        // Fix class members.
+        programClassFile.fieldsAccept(this);
+        programClassFile.methodsAccept(this);
+
+        // Fix the attributes.
+        programClassFile.attributesAccept(this);
+    }
+
+
+    public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+    {
+    }
+
+
+    // Implementations for CpInfoVisitor.
+
+    public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+    public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+    public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+    public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+    public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+    public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+    public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+
+
+    public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
+    {
+        // Do we know the referenced field?
+        MemberInfo referencedMemberInfo = fieldrefCpInfo.referencedMemberInfo;
+        if (referencedMemberInfo != null)
+        {
+            ClassFile referencedClassFile = fieldrefCpInfo.referencedClassFile;
+
+            // Does it have a new name or type?
+            String newName = referencedMemberInfo.getName(referencedClassFile);
+            String newType = referencedMemberInfo.getDescriptor(referencedClassFile);
+
+            if (!fieldrefCpInfo.getName(classFile).equals(newName) ||
+                !fieldrefCpInfo.getType(classFile).equals(newType))
+            {
+                if (DEBUG)
+                {
+                    debug(classFile, fieldrefCpInfo, referencedClassFile, referencedMemberInfo);
+                }
+
+                // Update the name and type index.
+                fieldrefCpInfo.u2nameAndTypeIndex =
+                    constantPoolEditor.addNameAndTypeCpInfo((ProgramClassFile)classFile,
+                                                            newName,
+                                                            newType);
+            }
+        }
+    }
+
+
+    public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
+    {
+        // Do we know the referenced interface method?
+        MemberInfo referencedMemberInfo = interfaceMethodrefCpInfo.referencedMemberInfo;
+        if (referencedMemberInfo != null)
+        {
+            ClassFile referencedClassFile = interfaceMethodrefCpInfo.referencedClassFile;
+
+            // Does it have a new name or type?
+            String newName = referencedMemberInfo.getName(referencedClassFile);
+            String newType = referencedMemberInfo.getDescriptor(referencedClassFile);
+
+            if (!interfaceMethodrefCpInfo.getName(classFile).equals(newName) ||
+                !interfaceMethodrefCpInfo.getType(classFile).equals(newType))
+            {
+                if (DEBUG)
+                {
+                    debug(classFile, interfaceMethodrefCpInfo, referencedClassFile, referencedMemberInfo);
+                }
+
+                // Update the name and type index.
+                interfaceMethodrefCpInfo.u2nameAndTypeIndex =
+                    constantPoolEditor.addNameAndTypeCpInfo((ProgramClassFile)classFile,
+                                                            newName,
+                                                            newType);
+
+                // Remember that the stack sizes of the methods in this class
+                // may have changed.
+                stackSizesMayHaveChanged = true;
+            }
+
+            // Check if this is an interface method.
+            isInterfaceMethod = true;
+            classFile.constantPoolEntryAccept(interfaceMethodrefCpInfo.u2classIndex, this);
+
+            // Has the method become a non-interface method?
+            if (!isInterfaceMethod)
+            {
+                if (DEBUG)
+                {
+                    System.out.println("MemberReferenceFixer:");
+                    System.out.println("  Class file     = "+classFile.getName());
+                    System.out.println("  Ref class file = "+referencedClassFile.getName());
+                    System.out.println("  Ref method     = "+interfaceMethodrefCpInfo.getName(classFile)+interfaceMethodrefCpInfo.getType(classFile));
+                    System.out.println("    -> ordinary method");
+                }
+
+                // Replace the interface method reference by a method reference.
+                ((ProgramClassFile)classFile).constantPool[this.cpIndex] =
+                    new MethodrefCpInfo(interfaceMethodrefCpInfo.u2classIndex,
+                                        interfaceMethodrefCpInfo.u2nameAndTypeIndex,
+                                        referencedClassFile,
+                                        referencedMemberInfo);
+            }
+        }
+    }
+
+
+    public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+    {
+        // Do we know the referenced method?
+        MemberInfo referencedMemberInfo = methodrefCpInfo.referencedMemberInfo;
+        if (referencedMemberInfo != null)
+        {
+            ClassFile referencedClassFile = methodrefCpInfo.referencedClassFile;
+
+            // Does it have a new name or type?
+            String newName = referencedMemberInfo.getName(referencedClassFile);
+            String newType = referencedMemberInfo.getDescriptor(referencedClassFile);
+
+            if (!methodrefCpInfo.getName(classFile).equals(newName) ||
+                !methodrefCpInfo.getType(classFile).equals(newType))
+            {
+                if (DEBUG)
+                {
+                    debug(classFile, methodrefCpInfo, referencedClassFile, referencedMemberInfo);
+                }
+
+                // Update the name and type index.
+                methodrefCpInfo.u2nameAndTypeIndex =
+                    constantPoolEditor.addNameAndTypeCpInfo((ProgramClassFile)classFile,
+                                                            newName,
+                                                            newType);
+
+                // Remember that the stack sizes of the methods in this class
+                // may have changed.
+                stackSizesMayHaveChanged = true;
+            }
+
+            // Check if this is an interface method.
+            isInterfaceMethod = false;
+            classFile.constantPoolEntryAccept(methodrefCpInfo.u2classIndex, this);
+
+            // Has the method become an interface method?
+            if (isInterfaceMethod)
+            {
+                if (DEBUG)
+                {
+                    System.out.println("MemberReferenceFixer:");
+                    System.out.println("  Class file     = "+classFile.getName());
+                    System.out.println("  Ref class file = "+referencedClassFile.getName());
+                    System.out.println("  Ref method     = "+methodrefCpInfo.getName(classFile)+methodrefCpInfo.getType(classFile));
+                    System.out.println("    -> interface method");
+                }
+
+                // Replace the method reference by an interface method reference.
+                ((ProgramClassFile)classFile).constantPool[this.cpIndex] =
+                    new InterfaceMethodrefCpInfo(methodrefCpInfo.u2classIndex,
+                                                 methodrefCpInfo.u2nameAndTypeIndex,
+                                                 referencedClassFile,
+                                                 referencedMemberInfo);
+            }
+        }
+    }
+
+
+    public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+    {
+        // Check if this class entry refers to an interface class.
+        ClassFile referencedClassFile = classCpInfo.referencedClassFile;
+        if (referencedClassFile != null)
+        {
+            isInterfaceMethod = (referencedClassFile.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE) != 0;
+        }
+    }
+
+
+    // Implementations for MemberInfoVisitor.
+
+    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+    {
+        // Fix the attributes.
+        programFieldInfo.attributesAccept(programClassFile, this);
+    }
+
+
+    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+    {
+        // Fix the attributes.
+        programMethodInfo.attributesAccept(programClassFile, this);
+    }
+
+
+    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+
+
+    // Implementations for AttrInfoVisitor.
+
+    public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+    public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+    public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+    public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+    public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+    public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
+    public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
+    public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+    public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+    public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+    public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+    public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
+
+
+    public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo)
+    {
+        MemberInfo referencedMemberInfo = enclosingMethodAttrInfo.referencedMethodInfo;
+        if (referencedMemberInfo != null)
+        {
+            ClassFile referencedClassFile = enclosingMethodAttrInfo.referencedClassFile;
+
+            // Does it have a new class?
+            if (!enclosingMethodAttrInfo.getClassName(classFile).equals(referencedClassFile.getName()))
+            {
+                // Update the class index.
+                enclosingMethodAttrInfo.u2classIndex =
+                    constantPoolEditor.addClassCpInfo((ProgramClassFile)classFile,
+                                                      referencedClassFile);
+            }
+
+            // Does it have a new name or type?
+            if (!enclosingMethodAttrInfo.getName(classFile).equals(referencedMemberInfo.getName(referencedClassFile)) ||
+                !enclosingMethodAttrInfo.getType(classFile).equals(referencedMemberInfo.getDescriptor(referencedClassFile)))
+            {
+                // Update the name and type index.
+                enclosingMethodAttrInfo.u2nameAndTypeIndex =
+                    constantPoolEditor.addNameAndTypeCpInfo((ProgramClassFile)classFile,
+                                                            referencedMemberInfo.getName(referencedClassFile),
+                                                            referencedMemberInfo.getDescriptor(referencedClassFile));
+            }
+        }
+    }
+
+
+    public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+    {
+        // Recompute the maximum stack size if necessary.
+        if (stackSizesMayHaveChanged)
+        {
+            stackSizeUpdater.visitCodeAttrInfo(classFile, methodInfo, codeAttrInfo);
+        }
+
+        // Fix the nested attributes.
+        codeAttrInfo.attributesAccept(classFile, methodInfo, this);
+    }
+
+
+    public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo)
+    {
+        // Fix the annotations.
+        runtimeVisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+    }
+
+
+    public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo)
+    {
+        // Fix the annotations.
+        runtimeInvisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+    }
+
+
+    public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo)
+    {
+        // Fix the annotations.
+        runtimeVisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+    }
+
+
+    public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo)
+    {
+        // Fix the annotations.
+        runtimeInvisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+    }
+
+
+    public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo)
+    {
+        // Fix the annotation.
+        annotationDefaultAttrInfo.defaultValueAccept(classFile, this);
+    }
+
+
+    // Implementations for AnnotationVisitor.
+
+    public void visitAnnotation(ClassFile classFile, Annotation annotation)
+    {
+        // Fix the element values.
+        annotation.elementValuesAccept(classFile, this);
+    }
+
+
+    // Implementations for ElementValueVisitor.
+
+    public void visitConstantElementValue(ClassFile classFile, Annotation annotation, ConstantElementValue constantElementValue)
+    {
+        fixElementValue(classFile, annotation, constantElementValue);
+    }
+
+
+    public void visitEnumConstantElementValue(ClassFile classFile, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
+    {
+        fixElementValue(classFile, annotation, enumConstantElementValue);
+    }
+
+
+    public void visitClassElementValue(ClassFile classFile, Annotation annotation, ClassElementValue classElementValue)
+    {
+        fixElementValue(classFile, annotation, classElementValue);
+    }
+
+
+    public void visitAnnotationElementValue(ClassFile classFile, Annotation annotation, AnnotationElementValue annotationElementValue)
+    {
+        fixElementValue(classFile, annotation, annotationElementValue);
+
+        // Fix the annotation.
+        annotationElementValue.annotationAccept(classFile, this);
+    }
+
+
+    public void visitArrayElementValue(ClassFile classFile, Annotation annotation, ArrayElementValue arrayElementValue)
+    {
+        fixElementValue(classFile, annotation, arrayElementValue);
+
+        // Fix the element values.
+        arrayElementValue.elementValuesAccept(classFile, annotation, this);
+    }
+
+
+    // Small utility methods.
+
+    /**
+     * Fixs the method reference of the element value, if any.
+     */
+    private void fixElementValue(ClassFile    classFile,
+                                 Annotation   annotation,
+                                 ElementValue elementValue)
+    {
+        // Do we know the referenced method?
+        MemberInfo referencedMemberInfo = elementValue.referencedMethodInfo;
+        if (referencedMemberInfo != null)
+        {
+            // Does it have a new name or type?
+            String methodName    = elementValue.getMethodName(classFile);
+            String newMethodName = referencedMemberInfo.getName(annotation.referencedClassFiles[0]);
+            if (!methodName.equals(newMethodName))
+            {
+                // Update the element name index.
+                elementValue.u2elementName =
+                    constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
+                                                     newMethodName);
+            }
+        }
+    }
+
+
+    private void debug(ClassFile  classFile,
+                       RefCpInfo  refCpInfo,
+                       ClassFile  referencedClassFile,
+                       MemberInfo referencedMemberInfo)
+    {
+        System.out.println("MemberReferenceFixer:");
+        System.out.println("  Class file      = "+classFile.getName());
+        System.out.println("  Ref class file  = "+referencedClassFile.getName());
+        System.out.println("  Ref member name = "+refCpInfo.getName(classFile));
+        System.out.println("                 -> "+referencedMemberInfo.getName(referencedClassFile));
+        System.out.println("  Ref descriptor  = "+refCpInfo.getType(classFile));
+        System.out.println("                 -> "+referencedMemberInfo.getDescriptor(referencedClassFile));
+    }
+}
diff --git a/src/proguard/classfile/editor/MethodInvocationFixer.java b/src/proguard/classfile/editor/MethodInvocationFixer.java
new file mode 100644
index 0000000..579d71e
--- /dev/null
+++ b/src/proguard/classfile/editor/MethodInvocationFixer.java
@@ -0,0 +1,284 @@
+/* $Id: MethodInvocationFixer.java,v 1.3 2005/06/11 13:21:35 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.editor;
+
+import proguard.classfile.*;
+import proguard.classfile.util.ClassUtil;
+import proguard.classfile.attribute.CodeAttrInfo;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This InstructionVisitor fixes all inappropriate special/virtual/static/interface
+ * invocations.
+ *
+ * @author Eric Lafortune
+ */
+public class MethodInvocationFixer
+implements   InstructionVisitor,
+             CpInfoVisitor,
+             MemberInfoVisitor
+{
+    private static final boolean DEBUG = false;
+
+    private CodeAttrInfoEditor codeAttrInfoEditor;
+
+    // Return values for the visitor methods.
+    private boolean isMethodInvocation;
+    private int     accessFlags;
+    private boolean isInitializer;
+    private boolean isInterfaceMethod;
+    private int     parameterSize;
+
+
+    /**
+     * Creates a new MethodInvocationFixer.
+     * @param codeAttrInfoEditor a code editor that can be used for
+     *                           accumulating changes to the code.
+     */
+    public MethodInvocationFixer(CodeAttrInfoEditor codeAttrInfoEditor)
+    {
+        this.codeAttrInfoEditor = codeAttrInfoEditor;
+    }
+
+
+    // Implementations for InstructionVisitor.
+
+    public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
+    public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction) {}
+    public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
+    public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
+    public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
+
+
+    public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
+    {
+        int cpIndex  = cpInstruction.cpIndex;
+        int constant = cpInstruction.constant;
+
+        // Get the constant pool entry's information.
+        isMethodInvocation = false;
+        isInterfaceMethod  = false;
+        accessFlags        = 0;
+        parameterSize      = constant;
+
+        classFile.constantPoolEntryAccept(cpIndex, this);
+
+        // Is it a method invocation?
+        if (isMethodInvocation)
+        {
+            if (DEBUG)
+            {
+            }
+
+            // Do we need to update the opcode?
+            byte opcode = cpInstruction.opcode;
+
+            // Is the method static?
+            if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0)
+            {
+                // But is it not a static invocation?
+                if (opcode != InstructionConstants.OP_INVOKESTATIC)
+                {
+                    // Replace the invocation by an invokestatic instruction.
+                    Instruction replacementInstruction =
+                        new CpInstruction(InstructionConstants.OP_INVOKESTATIC,
+                                          cpIndex).shrink();
+
+                    codeAttrInfoEditor.replaceInstruction(offset, replacementInstruction);
+
+                    if (DEBUG)
+                    {
+                        debug(classFile, methodInfo, offset, cpInstruction, replacementInstruction);
+                    }
+                }
+            }
+
+            // Is the method private, or an instance initializer?
+            else if ((accessFlags & ClassConstants.INTERNAL_ACC_PRIVATE) != 0 ||
+                     isInitializer)
+            {
+                // But is it not a special invocation?
+                if (opcode != InstructionConstants.OP_INVOKESPECIAL)
+                {
+                    // Replace the invocation by an invokespecial instruction.
+                    Instruction replacementInstruction =
+                        new CpInstruction(InstructionConstants.OP_INVOKESPECIAL,
+                                          cpIndex).shrink();
+
+                    codeAttrInfoEditor.replaceInstruction(offset, replacementInstruction);
+
+                    if (DEBUG)
+                    {
+                        debug(classFile, methodInfo, offset, cpInstruction, replacementInstruction);
+                    }
+                }
+            }
+
+            // Is the method an interface method?
+            else if (isInterfaceMethod)
+            {
+                // But is it not an interface invocation, or is the parameter
+                // size incorrect?
+                if (opcode != InstructionConstants.OP_INVOKEINTERFACE ||
+                    parameterSize != constant)
+                {
+                    // Fix the parameter size of the interface invocation.
+                    Instruction replacementInstruction =
+                        new CpInstruction(InstructionConstants.OP_INVOKEINTERFACE,
+                                          cpIndex,
+                                          parameterSize).shrink();
+
+                    codeAttrInfoEditor.replaceInstruction(offset, replacementInstruction);
+
+                    if (DEBUG)
+                    {
+                        debug(classFile, methodInfo, offset, cpInstruction, replacementInstruction);
+                    }
+                }
+            }
+
+            // The method is not static, private, an instance initializer, or
+            // an interface method.
+            else
+            {
+                // But is it not a virtual invocation (or a special invocation,
+                // which is allowed for super calls)?
+                if (opcode != InstructionConstants.OP_INVOKEVIRTUAL &&
+                    opcode != InstructionConstants.OP_INVOKESPECIAL)
+                {
+                    // Replace the invocation by an invokevirtual instruction.
+                    Instruction replacementInstruction =
+                        new CpInstruction(InstructionConstants.OP_INVOKEVIRTUAL,
+                                          cpIndex).shrink();
+
+                    codeAttrInfoEditor.replaceInstruction(offset, replacementInstruction);
+
+                    if (DEBUG)
+                    {
+                        debug(classFile, methodInfo, offset, cpInstruction, replacementInstruction);
+                    }
+                }
+            }
+        }
+    }
+
+
+    // Implementations for CpInfoVisitor.
+
+    public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+    public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+    public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+    public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+    public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+    public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
+    public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+    public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+
+
+    public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
+    {
+        // Check if this is an interface method.
+        classFile.constantPoolEntryAccept(interfaceMethodrefCpInfo.u2classIndex, this);
+
+        // Get the referenced method's access flags.
+        interfaceMethodrefCpInfo.referencedMemberInfoAccept(this);
+    }
+
+
+    public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+    {
+        // Check if this is an interface method.
+        classFile.constantPoolEntryAccept(methodrefCpInfo.u2classIndex, this);
+
+        // Get the referenced method's access flags.
+        methodrefCpInfo.referencedMemberInfoAccept(this);
+    }
+
+
+    public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+    {
+        // Check if this class entry refers to an interface class.
+        ClassFile referencedClassFile = classCpInfo.referencedClassFile;
+        if (referencedClassFile != null)
+        {
+            isInterfaceMethod = (referencedClassFile.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE) != 0;
+        }
+    }
+
+
+    // Implementations for MemberInfoVisitor.
+
+    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
+
+    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+    {
+        visitMethodInfo(programClassFile, programMethodInfo);
+    }
+
+
+    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+
+    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+    {
+        visitMethodInfo(libraryClassFile, libraryMethodInfo);
+    }
+
+
+    private void visitMethodInfo(ClassFile classFile, MethodInfo methodInfo)
+    {
+        // We've found a method definition.
+        isMethodInvocation = true;
+
+        // Get the method's access flags.
+        accessFlags = methodInfo.getAccessFlags();
+
+        // Check if this is an instance initializer.
+        isInitializer = methodInfo.getName(classFile).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT);
+
+        // Remember the parameter size of interface methods.
+        if (isInterfaceMethod)
+        {
+            parameterSize = ClassUtil.internalMethodParameterSize(methodInfo.getDescriptor(classFile)) + 1 << 8;
+        }
+    }
+
+
+    // Small utility methods.
+
+    private void debug(ClassFile     classFile,
+                       MethodInfo    methodInfo,
+                       int           offset,
+                       CpInstruction cpInstruction,
+                       Instruction   replacementInstruction)
+    {
+        System.out.println("MethodInvocationFixer:");
+        System.out.println("  Class file       = "+classFile.getName());
+        System.out.println("  Method           = "+methodInfo.getName(classFile)+methodInfo.getDescriptor(classFile));
+        System.out.println("  Instruction      = "+cpInstruction.toString(offset));
+        System.out.println("  Interface method = "+isInterfaceMethod);
+        if (isInterfaceMethod)
+        {
+            System.out.println("  Parameter size   = "+parameterSize);
+        }
+        System.out.println("  Replacement instruction = "+replacementInstruction.toString(offset));
+    }
+}
diff --git a/src/proguard/classfile/editor/StackSizeUpdater.java b/src/proguard/classfile/editor/StackSizeUpdater.java
index 08cd042..ec78170 100644
--- a/src/proguard/classfile/editor/StackSizeUpdater.java
+++ b/src/proguard/classfile/editor/StackSizeUpdater.java
@@ -1,8 +1,8 @@
-/* $Id: StackSizeUpdater.java,v 1.12 2004/11/20 15:41:24 eric Exp $
+/* $Id: StackSizeUpdater.java,v 1.14 2005/06/25 22:02:22 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -21,6 +21,7 @@
 package proguard.classfile.editor;
 
 import proguard.classfile.*;
+import proguard.classfile.util.ClassUtil;
 import proguard.classfile.attribute.*;
 import proguard.classfile.attribute.annotation.*;
 import proguard.classfile.instruction.*;
@@ -91,6 +92,15 @@ implements AttrInfoVisitor,
 //            classFile.getName().equals("abc/Def") &&
 //            methodInfo.getName(classFile).equals("abc");
 
+        if (DEBUG)
+        {
+            System.out.println("Class "+ClassUtil.externalClassName(classFile.getName()));
+            System.out.println("Method "+ClassUtil.externalFullMethodDescription(classFile.getName(),
+                                                                                 0,
+                                                                                 methodInfo.getName(classFile),
+                                                                                 methodInfo.getDescriptor(classFile)));
+        }
+
         // Try to reuse the previous array.
         int codeLength = codeAttrInfo.u4codeLength;
         if (evaluated.length < codeLength)
diff --git a/src/proguard/obfuscate/AttributeShrinker.java b/src/proguard/classfile/editor/VariableEditor.java
similarity index 52%
copy from src/proguard/obfuscate/AttributeShrinker.java
copy to src/proguard/classfile/editor/VariableEditor.java
index 1fb95ef..d66b996 100644
--- a/src/proguard/obfuscate/AttributeShrinker.java
+++ b/src/proguard/classfile/editor/VariableEditor.java
@@ -1,8 +1,8 @@
-/* $Id: AttributeShrinker.java,v 1.16 2004/10/10 20:56:58 eric Exp $
+/* $Id: VariableEditor.java,v 1.4 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -18,83 +18,106 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-package proguard.obfuscate;
+package proguard.classfile.editor;
 
 import proguard.classfile.*;
 import proguard.classfile.attribute.*;
 import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.instruction.*;
 import proguard.classfile.visitor.*;
 
 /**
- * This ClassFileVisitor removes attributes that are not marked
- * as being used or required.
- *
- * @see AttributeUsageMarker
+ * This AttrInfoVisitor accumulates specified changes to local variables, and
+ * then applies these accumulated changes to the code attributes that it visits.
  *
  * @author Eric Lafortune
  */
-public class AttributeShrinker
-  implements ClassFileVisitor,
-             MemberInfoVisitor,
-             AttrInfoVisitor
+public class VariableEditor
+  implements AttrInfoVisitor
 {
-    // Implementations for ClassFileVisitor.
+    private VariableRemapper variableRemapper;
 
-    public void visitProgramClassFile(ProgramClassFile programClassFile)
-    {
-        // Compact the array for class attributes.
-        programClassFile.u2attributesCount =
-            shrinkArray(programClassFile.attributes,
-                        programClassFile.u2attributesCount);
-
-        // Compact the attributes in fields, methods, and class attributes,
-        programClassFile.fieldsAccept(this);
-        programClassFile.methodsAccept(this);
-        programClassFile.attributesAccept(this);
-    }
+    private boolean          modified;
 
+    private boolean[]        deleted;
 
-    public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
-    {
-        // Library class files are left unchanged.
-    }
-
+    private int[]            variableMap;
 
-    // Implementations for MemberInfoVisitor.
 
-    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+    /**
+     * Creates a new VariableEditor.
+     * @param codeLength an estimate of the maximum length of all the code
+     *                   that will be edited.
+     * @param maxLocals  an estimate of the maximum length of all the local
+     *                   variable frames that will be edited.
+     */
+    public VariableEditor(int codeLength, int maxLocals)
     {
-        visitMemberInfo(programClassFile, programFieldInfo);
+        variableRemapper = new VariableRemapper(codeLength);
+        deleted          = new boolean[maxLocals];
+        variableMap      = new int[maxLocals];
+
+        for (int index = 0; index < maxLocals; index++)
+        {
+            variableMap[index] = -1;
+        }
     }
 
 
-    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+    /**
+     * Resets the accumulated code changes.
+     * @param maxLocals the length of the local variable frame that will be
+     *                  edited next.
+     */
+    public void reset(int maxLocals)
     {
-        visitMemberInfo(programClassFile, programMethodInfo);
+        // Try to reuse the previous array.
+        if (deleted.length < maxLocals)
+        {
+            deleted = new boolean[maxLocals];
+        }
+        else
+        {
+            for (int index = 0; index < maxLocals; index++)
+            {
+                deleted[index]     = false;
+                variableMap[index] = -1;
+            }
+        }
+
+        modified = false;
     }
 
 
-    private void visitMemberInfo(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+
+
+    /**
+     * Remembers to delete the given variable.
+     * @param variableIndex the index of the variable to be deleted.
+     */
+    public void deleteVariable(int variableIndex)
     {
-        // Compact the attributes array.
-        programMemberInfo.u2attributesCount =
-            shrinkArray(programMemberInfo.attributes,
-                        programMemberInfo.u2attributesCount);
+        deleted[variableIndex] = true;
 
-        // Compact any attributes of the remaining attributes.
-        programMemberInfo.attributesAccept(programClassFile, this);
+        modified = true;
     }
 
 
-    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+    /**
+     * Returns whether the given variable at the given offset has deleted.
+     */
+    public boolean isDeleted(int instructionOffset)
     {
-        // Library class files are left unchanged.
+        return deleted[instructionOffset];
     }
 
 
-    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+    /**
+     * Returns whether any oarameter has been modified.
+     */
+    public boolean isModified()
     {
-        // Library class files are left unchanged.
+        return modified;
     }
 
 
@@ -122,39 +145,38 @@ public class AttributeShrinker
 
     public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
     {
-        // Compact the attributes array.
-        codeAttrInfo.u2attributesCount =
-            shrinkArray(codeAttrInfo.attributes,
-                        codeAttrInfo.u2attributesCount);
-    }
-
+        // Avoid doing any work if nothing is changing anyway.
+        if (!modified)
+        {
+            return;
+        }
 
-    // Small utility methods.
+        int oldMaxLocals = codeAttrInfo.u2maxLocals;
 
-    /**
-     * Removes all VisitorAccepter objects that are not marked as being used
-     * from the given array.
-     * @return the new number of VisitorAccepter objects.
-     */
-    private static int shrinkArray(VisitorAccepter[] array, int length)
-    {
-        int counter = 0;
+        // Make sure there is a sufficiently large variable map.
+        if (variableMap == null ||
+            variableMap.length < oldMaxLocals)
+        {
+            variableMap = new int[oldMaxLocals];
+        }
 
-        // Shift the used objects together.
-        for (int index = 0; index < length; index++)
+        // Fill out the variable map.
+        int newVariableIndex = 0;
+        for (int oldVariableIndex = 0; oldVariableIndex < oldMaxLocals; oldVariableIndex++)
         {
-            if (AttributeUsageMarker.isUsed(array[index]))
+            if (!deleted[oldVariableIndex])
             {
-                array[counter++] = array[index];
+                variableMap[oldVariableIndex] = newVariableIndex++;
             }
         }
 
-        // Clear the remaining array elements.
-        for (int index = counter; index < length; index++)
-        {
-            array[index] = null;
-        }
+        // Set the map.
+        variableRemapper.setVariableMap(variableMap);
+
+        // Remap the variables.
+        variableRemapper.visitCodeAttrInfo(classFile, methodInfo, codeAttrInfo);
 
-        return counter;
+        // Update the length of local variable frame.
+        codeAttrInfo.u2maxLocals = newVariableIndex;
     }
 }
diff --git a/src/proguard/classfile/editor/VariableRemapper.java b/src/proguard/classfile/editor/VariableRemapper.java
new file mode 100644
index 0000000..a804e31
--- /dev/null
+++ b/src/proguard/classfile/editor/VariableRemapper.java
@@ -0,0 +1,223 @@
+/* $Id: VariableRemapper.java,v 1.4 2005/06/11 13:21:35 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.classfile.editor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.instruction.*;
+
+/**
+ * This AttrInfoVisitor remaps variable indexes in all attributes that it
+ * visits, based on a given index map.
+ *
+ * @author Eric Lafortune
+ */
+public class VariableRemapper
+  implements AttrInfoVisitor,
+             InstructionVisitor,
+             LocalVariableInfoVisitor,
+             LocalVariableTypeInfoVisitor
+{
+    private CodeAttrInfoEditor codeAttrInfoEditor;
+
+    private int[] variableMap;
+
+
+    /**
+     * Creates a new VariableRemapper.
+     * @param codeLength an estimate of the maximum length of all the code that
+     *                   will be edited.
+     */
+    public VariableRemapper(int codeLength)
+    {
+        codeAttrInfoEditor = new CodeAttrInfoEditor(codeLength);
+    }
+
+
+    /**
+     * Sets the given mapping of old variable indexes to their new indexes.
+     * Variables that should disappear can be mapped to -1.
+     */
+    public void setVariableMap(int[] variableMap)
+    {
+        this.variableMap = variableMap;
+    }
+
+
+    // Implementations for AttrInfoVisitor.
+
+    public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+    public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+    public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
+    public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+    public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+    public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+    public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+    public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+    public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+    public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+    public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
+    public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo) {}
+    public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo) {}
+    public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo) {}
+    public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo) {}
+    public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {}
+
+
+    public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+    {
+        // Initially, the code attribute editor doesn't contain any changes.
+        codeAttrInfoEditor.reset(codeAttrInfo.u4codeLength);
+
+        // Remap the variables of the instructions.
+        codeAttrInfo.instructionsAccept(classFile, methodInfo, this);
+
+        // Apply the code atribute editor.
+        codeAttrInfoEditor.visitCodeAttrInfo(classFile, methodInfo, codeAttrInfo);
+
+        // Remap the variables of the attributes.
+        codeAttrInfo.attributesAccept(classFile, methodInfo, this);
+    }
+
+
+    public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo)
+    {
+        // Remap the variable references of the local variables.
+        localVariableTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
+
+        // Remove local variables that haven't been mapped.
+        localVariableTableAttrInfo.u2localVariableTableLength =
+            removeEmptyLocalVariables(localVariableTableAttrInfo.localVariableTable,
+                                      localVariableTableAttrInfo.u2localVariableTableLength);
+    }
+
+
+    public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo)
+    {
+        // Remap the variable references of the local variables.
+        localVariableTypeTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
+
+        // Remove local variables that haven't been mapped.
+        localVariableTypeTableAttrInfo.u2localVariableTypeTableLength =
+            removeEmptyLocalVariableTypes(localVariableTypeTableAttrInfo.localVariableTypeTable,
+                                          localVariableTypeTableAttrInfo.u2localVariableTypeTableLength);
+    }
+
+
+    // Implementations for LocalVariableInfoVisitor.
+
+    public void visitLocalVariableInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableInfo localVariableInfo)
+    {
+        localVariableInfo.u2index =
+            remapVariable(localVariableInfo.u2index);
+    }
+
+
+    // Implementations for LocalVariableTypeInfoVisitor.
+
+    public void visitLocalVariableTypeInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeInfo localVariableTypeInfo)
+    {
+        localVariableTypeInfo.u2index =
+            remapVariable(localVariableTypeInfo.u2index);
+    }
+
+
+    // Implementations for InstructionVisitor.
+
+    public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
+    public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction) {}
+    public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
+    public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
+    public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
+
+
+    public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction)
+    {
+        // Is the new variable index different from the original one?
+        int oldVariableIndex = variableInstruction.variableIndex;
+        int newVariableIndex = remapVariable(oldVariableIndex);
+        if (newVariableIndex != oldVariableIndex)
+        {
+            // Replace the instruction.
+            variableInstruction = new VariableInstruction().copy(variableInstruction);
+            variableInstruction.variableIndex = newVariableIndex;
+            variableInstruction.shrink();
+
+            codeAttrInfoEditor.replaceInstruction(offset, variableInstruction);
+        }
+    }
+
+
+    // Small utility methods.
+
+    /**
+     * Returns the new variable index of the given variable.
+     */
+    private int remapVariable(int variableIndex)
+    {
+        return variableMap[variableIndex];
+    }
+
+
+    /**
+     * Returns the given list of local variables, without the ones that have
+     * been removed.
+     */
+    private int removeEmptyLocalVariables(LocalVariableInfo[] localVariableInfos,
+                                          int                 localVariableInfoCount)
+    {
+        // Overwrite all empty local variable entries.
+        int newIndex = 0;
+        for (int index = 0; index < localVariableInfoCount; index++)
+        {
+            LocalVariableInfo localVariableInfo = localVariableInfos[index];
+            if (localVariableInfo.u2index >= 0)
+            {
+                localVariableInfos[newIndex++] = localVariableInfo;
+            }
+        }
+
+        return newIndex;
+    }
+
+
+    /**
+     * Returns the given list of local variable types, without the ones that
+     * have been removed.
+     */
+    private int removeEmptyLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos,
+                                              int                     localVariableTypeInfoCount)
+    {
+        // Overwrite all empty local variable type entries.
+        int newIndex = 0;
+        for (int index = 0; index < localVariableTypeInfoCount; index++)
+        {
+            LocalVariableTypeInfo localVariableTypeInfo = localVariableTypeInfos[index];
+            if (localVariableTypeInfo.u2index >= 0)
+            {
+                localVariableTypeInfos[newIndex++] = localVariableTypeInfo;
+            }
+        }
+
+        return newIndex;
+    }
+}
diff --git a/src/proguard/classfile/instruction/BranchInstruction.java b/src/proguard/classfile/instruction/BranchInstruction.java
index 67d015d..0a0726c 100644
--- a/src/proguard/classfile/instruction/BranchInstruction.java
+++ b/src/proguard/classfile/instruction/BranchInstruction.java
@@ -1,8 +1,8 @@
-/* $Id: BranchInstruction.java,v 1.14 2004/10/10 20:56:58 eric Exp $
+/* $Id: BranchInstruction.java,v 1.15 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/instruction/CpInstruction.java b/src/proguard/classfile/instruction/CpInstruction.java
index f8caa07..8cc1d3b 100644
--- a/src/proguard/classfile/instruction/CpInstruction.java
+++ b/src/proguard/classfile/instruction/CpInstruction.java
@@ -1,8 +1,8 @@
-/* $Id: CpInstruction.java,v 1.19 2004/12/11 16:35:23 eric Exp $
+/* $Id: CpInstruction.java,v 1.20 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/instruction/Instruction.java b/src/proguard/classfile/instruction/Instruction.java
index e0f9b4f..9eafaca 100644
--- a/src/proguard/classfile/instruction/Instruction.java
+++ b/src/proguard/classfile/instruction/Instruction.java
@@ -1,8 +1,8 @@
-/* $Id: Instruction.java,v 1.22 2004/12/11 00:12:41 eric Exp $
+/* $Id: Instruction.java,v 1.23 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/instruction/InstructionFactory.java b/src/proguard/classfile/instruction/InstructionFactory.java
index b381db2..7f72b82 100644
--- a/src/proguard/classfile/instruction/InstructionFactory.java
+++ b/src/proguard/classfile/instruction/InstructionFactory.java
@@ -1,8 +1,8 @@
-/* $Id: InstructionFactory.java,v 1.5 2004/08/21 21:37:28 eric Exp $
+/* $Id: InstructionFactory.java,v 1.6 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/instruction/InstructionVisitor.java b/src/proguard/classfile/instruction/InstructionVisitor.java
index 3484c64..1af3da6 100644
--- a/src/proguard/classfile/instruction/InstructionVisitor.java
+++ b/src/proguard/classfile/instruction/InstructionVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: InstructionVisitor.java,v 1.13 2004/10/10 20:56:58 eric Exp $
+/* $Id: InstructionVisitor.java,v 1.14 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/instruction/LookUpSwitchInstruction.java b/src/proguard/classfile/instruction/LookUpSwitchInstruction.java
index bb371f9..8192bb3 100644
--- a/src/proguard/classfile/instruction/LookUpSwitchInstruction.java
+++ b/src/proguard/classfile/instruction/LookUpSwitchInstruction.java
@@ -1,8 +1,8 @@
-/* $Id: LookUpSwitchInstruction.java,v 1.6 2004/10/10 20:56:58 eric Exp $
+/* $Id: LookUpSwitchInstruction.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/instruction/MultiInstructionVisitor.java b/src/proguard/classfile/instruction/MultiInstructionVisitor.java
index 5894285..5f97342 100644
--- a/src/proguard/classfile/instruction/MultiInstructionVisitor.java
+++ b/src/proguard/classfile/instruction/MultiInstructionVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: MultiInstructionVisitor.java,v 1.3 2004/10/10 20:56:58 eric Exp $
+/* $Id: MultiInstructionVisitor.java,v 1.5 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -90,49 +90,61 @@ public class MultiInstructionVisitor implements InstructionVisitor
 
     public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction)
     {
+        simpleInstruction = this.simpleInstruction.copy(simpleInstruction);
+
         for (int index = 0; index < instructionVisitorCount; index++)
         {
-            instructionVisitors[index].visitSimpleInstruction(classFile, methodInfo, codeAttrInfo, offset, this.simpleInstruction.copy(simpleInstruction));
+            instructionVisitors[index].visitSimpleInstruction(classFile, methodInfo, codeAttrInfo, offset, simpleInstruction);
         }
     }
 
     public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction)
     {
+        variableInstruction = this.variableInstruction.copy(variableInstruction);
+
         for (int index = 0; index < instructionVisitorCount; index++)
         {
-            instructionVisitors[index].visitVariableInstruction(classFile, methodInfo, codeAttrInfo, offset, this.variableInstruction.copy(variableInstruction));
+            instructionVisitors[index].visitVariableInstruction(classFile, methodInfo, codeAttrInfo, offset, variableInstruction);
         }
     }
 
     public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
     {
+        cpInstruction = this.cpInstruction.copy(cpInstruction);
+
         for (int index = 0; index < instructionVisitorCount; index++)
         {
-            instructionVisitors[index].visitCpInstruction(classFile, methodInfo, codeAttrInfo, offset, this.cpInstruction.copy(cpInstruction));
+            instructionVisitors[index].visitCpInstruction(classFile, methodInfo, codeAttrInfo, offset, cpInstruction);
         }
     }
 
     public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction)
     {
+        branchInstruction = this.branchInstruction.copy(branchInstruction);
+
         for (int index = 0; index < instructionVisitorCount; index++)
         {
-            instructionVisitors[index].visitBranchInstruction(classFile, methodInfo, codeAttrInfo, offset, this.branchInstruction.copy(branchInstruction));
+            instructionVisitors[index].visitBranchInstruction(classFile, methodInfo, codeAttrInfo, offset, branchInstruction);
         }
     }
 
     public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction)
     {
+        tableSwitchInstruction = this.tableSwitchInstruction.copy(tableSwitchInstruction);
+
         for (int index = 0; index < instructionVisitorCount; index++)
         {
-            instructionVisitors[index].visitTableSwitchInstruction(classFile, methodInfo, codeAttrInfo, offset, this.tableSwitchInstruction.copy(tableSwitchInstruction));
+            instructionVisitors[index].visitTableSwitchInstruction(classFile, methodInfo, codeAttrInfo, offset, tableSwitchInstruction);
         }
     }
 
     public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
     {
+        lookUpSwitchInstruction = this.lookUpSwitchInstruction.copy(lookUpSwitchInstruction);
+
         for (int index = 0; index < instructionVisitorCount; index++)
         {
-            instructionVisitors[index].visitLookUpSwitchInstruction(classFile, methodInfo, codeAttrInfo, offset, this.lookUpSwitchInstruction.copy(lookUpSwitchInstruction));
+            instructionVisitors[index].visitLookUpSwitchInstruction(classFile, methodInfo, codeAttrInfo, offset, lookUpSwitchInstruction);
         }
     }
 }
diff --git a/src/proguard/classfile/instruction/SimpleInstruction.java b/src/proguard/classfile/instruction/SimpleInstruction.java
index 90942a0..98b013e 100644
--- a/src/proguard/classfile/instruction/SimpleInstruction.java
+++ b/src/proguard/classfile/instruction/SimpleInstruction.java
@@ -1,8 +1,8 @@
-/* $Id: SimpleInstruction.java,v 1.8 2004/10/10 20:56:58 eric Exp $
+/* $Id: SimpleInstruction.java,v 1.9 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/instruction/TableSwitchInstruction.java b/src/proguard/classfile/instruction/TableSwitchInstruction.java
index a2b269f..14debda 100644
--- a/src/proguard/classfile/instruction/TableSwitchInstruction.java
+++ b/src/proguard/classfile/instruction/TableSwitchInstruction.java
@@ -1,8 +1,8 @@
-/* $Id: TableSwitchInstruction.java,v 1.6 2004/10/10 20:56:58 eric Exp $
+/* $Id: TableSwitchInstruction.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/instruction/VariableInstruction.java b/src/proguard/classfile/instruction/VariableInstruction.java
index 7b60f6b..c51db2a 100644
--- a/src/proguard/classfile/instruction/VariableInstruction.java
+++ b/src/proguard/classfile/instruction/VariableInstruction.java
@@ -1,8 +1,8 @@
-/* $Id: VariableInstruction.java,v 1.17 2004/10/10 20:56:58 eric Exp $
+/* $Id: VariableInstruction.java,v 1.20 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -94,6 +94,51 @@ public class VariableInstruction extends Instruction
 
     public Instruction shrink()
     {
+        switch (opcode)
+        {
+            case InstructionConstants.OP_ILOAD_0:
+            case InstructionConstants.OP_ILOAD_1:
+            case InstructionConstants.OP_ILOAD_2:
+            case InstructionConstants.OP_ILOAD_3: opcode = InstructionConstants.OP_ILOAD; break;
+            case InstructionConstants.OP_LLOAD_0:
+            case InstructionConstants.OP_LLOAD_1:
+            case InstructionConstants.OP_LLOAD_2:
+            case InstructionConstants.OP_LLOAD_3: opcode = InstructionConstants.OP_LLOAD; break;
+            case InstructionConstants.OP_FLOAD_0:
+            case InstructionConstants.OP_FLOAD_1:
+            case InstructionConstants.OP_FLOAD_2:
+            case InstructionConstants.OP_FLOAD_3: opcode = InstructionConstants.OP_FLOAD; break;
+            case InstructionConstants.OP_DLOAD_0:
+            case InstructionConstants.OP_DLOAD_1:
+            case InstructionConstants.OP_DLOAD_2:
+            case InstructionConstants.OP_DLOAD_3: opcode = InstructionConstants.OP_DLOAD; break;
+            case InstructionConstants.OP_ALOAD_0:
+            case InstructionConstants.OP_ALOAD_1:
+            case InstructionConstants.OP_ALOAD_2:
+            case InstructionConstants.OP_ALOAD_3: opcode = InstructionConstants.OP_ALOAD; break;
+
+            case InstructionConstants.OP_ISTORE_0:
+            case InstructionConstants.OP_ISTORE_1:
+            case InstructionConstants.OP_ISTORE_2:
+            case InstructionConstants.OP_ISTORE_3: opcode = InstructionConstants.OP_ISTORE; break;
+            case InstructionConstants.OP_LSTORE_0:
+            case InstructionConstants.OP_LSTORE_1:
+            case InstructionConstants.OP_LSTORE_2:
+            case InstructionConstants.OP_LSTORE_3: opcode = InstructionConstants.OP_LSTORE; break;
+            case InstructionConstants.OP_FSTORE_0:
+            case InstructionConstants.OP_FSTORE_1:
+            case InstructionConstants.OP_FSTORE_2:
+            case InstructionConstants.OP_FSTORE_3: opcode = InstructionConstants.OP_FSTORE; break;
+            case InstructionConstants.OP_DSTORE_0:
+            case InstructionConstants.OP_DSTORE_1:
+            case InstructionConstants.OP_DSTORE_2:
+            case InstructionConstants.OP_DSTORE_3: opcode = InstructionConstants.OP_DSTORE; break;
+            case InstructionConstants.OP_ASTORE_0:
+            case InstructionConstants.OP_ASTORE_1:
+            case InstructionConstants.OP_ASTORE_2:
+            case InstructionConstants.OP_ASTORE_3: opcode = InstructionConstants.OP_ASTORE; break;
+        }
+
         // Is this instruction pointing to a variable with index from 0 to 3?
         if (variableIndex <= 3)
         {
diff --git a/src/proguard/classfile/util/AccessUtil.java b/src/proguard/classfile/util/AccessUtil.java
index af7c034..965a4e6 100644
--- a/src/proguard/classfile/util/AccessUtil.java
+++ b/src/proguard/classfile/util/AccessUtil.java
@@ -1,8 +1,8 @@
-/* $Id: AccessUtil.java,v 1.3 2004/08/15 12:39:30 eric Exp $
+/* $Id: AccessUtil.java,v 1.6 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -93,6 +93,11 @@ public class AccessUtil
      */
     public static int replaceAccessFlags(int accessFlags, int newAccessFlags)
     {
+        if (newAccessFlags == ClassConstants.INTERNAL_ACC_PRIVATE)
+        {
+            accessFlags &= ~ClassConstants.INTERNAL_ACC_FINAL;
+        }
+
         return (accessFlags    & ~ACCESS_MASK) |
                (newAccessFlags &  ACCESS_MASK);
     }
diff --git a/src/proguard/classfile/util/ClassFileClassForNameReferenceInitializer.java b/src/proguard/classfile/util/ClassFileClassForNameReferenceInitializer.java
index caeac24..d926107 100644
--- a/src/proguard/classfile/util/ClassFileClassForNameReferenceInitializer.java
+++ b/src/proguard/classfile/util/ClassFileClassForNameReferenceInitializer.java
@@ -1,8 +1,8 @@
-/* $Id: ClassFileClassForNameReferenceInitializer.java,v 1.14 2004/12/11 16:35:23 eric Exp $
+/* $Id: ClassFileClassForNameReferenceInitializer.java,v 1.16 2005/06/25 22:07:51 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -21,9 +21,10 @@
 package proguard.classfile.util;
 
 import proguard.classfile.*;
-import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.CodeAttrInfo;
 import proguard.classfile.instruction.*;
-import proguard.classfile.visitor.*;
+import proguard.classfile.visitor.CpInfoVisitor;
+import proguard.util.ClassNameListMatcher;
 
 
 /**
@@ -41,15 +42,17 @@ import proguard.classfile.visitor.*;
  *
  * @author Eric Lafortune
  */
-class      ClassFileClassForNameReferenceInitializer
-implements InstructionVisitor,
-           CpInfoVisitor
+public class ClassFileClassForNameReferenceInitializer
+  implements InstructionVisitor,
+             CpInfoVisitor
 {
-    private ClassPool programClassPool;
-    private boolean   note;
+    private ClassPool            programClassPool;
+    private ClassPool            libraryClassPool;
+    private boolean              note;
+    private ClassNameListMatcher noteExceptionMatcher;
 
     // Counter for notes.
-    private int       noteCount;
+    private int noteCount;
 
     // Fields to remember the previous StringCpInfo and MethodRefCpInfo objects
     // while visiting all instructions (to find Class.forName, class$, and
@@ -65,21 +68,27 @@ implements InstructionVisitor,
     /**
      * Creates a new ClassFileClassForNameReferenceInitializer that prints notes.
      */
-    public ClassFileClassForNameReferenceInitializer(ClassPool programClassPool)
+    public ClassFileClassForNameReferenceInitializer(ClassPool programClassPool,
+                                                     ClassPool libraryClassPool)
     {
-        this(programClassPool, true);
+        this(programClassPool, libraryClassPool, true, null);
     }
 
 
     /**
      * Creates a new ClassFileClassForNameReferenceInitializer that optionally
-     * prints notes.
+     * prints notes, with optional class specifications for which never to
+     * print notes.
      */
-    public ClassFileClassForNameReferenceInitializer(ClassPool programClassPool,
-                                                     boolean   note)
+    public ClassFileClassForNameReferenceInitializer(ClassPool            programClassPool,
+                                                     ClassPool            libraryClassPool,
+                                                     boolean              note,
+                                                     ClassNameListMatcher noteExceptionMatcher)
     {
-        this.programClassPool = programClassPool;
-        this.note             = note;
+        this.programClassPool     = programClassPool;
+        this.libraryClassPool     = libraryClassPool;
+        this.note                 = note;
+        this.noteExceptionMatcher = noteExceptionMatcher;
     }
 
 
@@ -238,7 +247,7 @@ implements InstructionVisitor,
         String externalClassName = stringCpInfo.getString(classFile);
         String internalClassName = ClassUtil.internalClassName(externalClassName);
 
-        stringCpInfo.referencedClassFile = programClassPool.getClass(internalClassName);
+        stringCpInfo.referencedClassFile = findClass(internalClassName);
     }
 
 
@@ -247,7 +256,9 @@ implements InstructionVisitor,
      */
     public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
     {
-        if (note)
+        if (note &&
+            (noteExceptionMatcher == null ||
+             !noteExceptionMatcher.matches(classCpInfo.getName(classFile))))
         {
             noteCount++;
             System.err.println("Note: " +
@@ -257,4 +268,23 @@ implements InstructionVisitor,
                                ")Class.forName(variable).newInstance()'");
         }
     }
+
+
+    /**
+     * Returns the class with the given name, either for the program class pool
+     * or from the library class pool, or <code>null</code> if it can't be found.
+     */
+    private ClassFile findClass(String name)
+    {
+        // First look for the class in the program class pool.
+        ClassFile classFile = programClassPool.getClass(name);
+
+        // Otherwise look for the class in the library class pool.
+        if (classFile == null)
+        {
+            classFile = libraryClassPool.getClass(name);
+        }
+
+        return classFile;
+    }
 }
diff --git a/src/proguard/classfile/util/ClassFileHierarchyInitializer.java b/src/proguard/classfile/util/ClassFileHierarchyInitializer.java
index 04941ec..fd35e4c 100644
--- a/src/proguard/classfile/util/ClassFileHierarchyInitializer.java
+++ b/src/proguard/classfile/util/ClassFileHierarchyInitializer.java
@@ -1,8 +1,8 @@
-/* $Id: ClassFileHierarchyInitializer.java,v 1.10 2004/12/11 16:35:23 eric Exp $
+/* $Id: ClassFileHierarchyInitializer.java,v 1.12 2005/06/25 22:07:51 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -73,8 +73,8 @@ public class ClassFileHierarchyInitializer
      * can't be found.
      */
     public ClassFileHierarchyInitializer(ClassPool programClassPool,
-                                ClassPool libraryClassPool,
-                                boolean   warn)
+                                         ClassPool libraryClassPool,
+                                         boolean   warn)
     {
         this.programClassPool = programClassPool;
         this.libraryClassPool = libraryClassPool;
diff --git a/src/proguard/classfile/util/ClassFileReferenceInitializer.java b/src/proguard/classfile/util/ClassFileReferenceInitializer.java
index 717fcd2..3343373 100644
--- a/src/proguard/classfile/util/ClassFileReferenceInitializer.java
+++ b/src/proguard/classfile/util/ClassFileReferenceInitializer.java
@@ -1,8 +1,8 @@
-/* $Id: ClassFileReferenceInitializer.java,v 1.28 2004/11/27 10:09:26 eric Exp $
+/* $Id: ClassFileReferenceInitializer.java,v 1.31 2005/06/25 22:07:51 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -40,8 +40,9 @@ import proguard.classfile.visitor.*;
  * All name and type constant pool entries get a list of direct references to
  * the classes listed in the type.
  * <p>
- * This visitor optionally prints warnings if some items can't be found, and
- * notes on the usage of <code>(SomeClass)Class.forName(variable).newInstance()</code>.
+ * This visitor optionally prints warnings if some items can't be found.
+ * <p>
+ * The class file hierarchy must be initialized before using this visitor.
  *
  * @author Eric Lafortune
  */
@@ -50,14 +51,11 @@ public class ClassFileReferenceInitializer
              MemberInfoVisitor,
              CpInfoVisitor,
              AttrInfoVisitor,
-             //LocalVariableInfoVisitor,
-             //LocalVariableTypeInfoVisitor,
+             LocalVariableInfoVisitor,
+             LocalVariableTypeInfoVisitor,
              AnnotationVisitor,
              ElementValueVisitor
 {
-    // A reusable object for checking whether referenced methods are Class.forName,...
-    private ClassFileClassForNameReferenceInitializer classFileClassForNameReferenceInitializer;
-
     private MemberFinder memberFinder = new MemberFinder();
 
     private ClassPool programClassPool;
@@ -75,7 +73,7 @@ public class ClassFileReferenceInitializer
     public ClassFileReferenceInitializer(ClassPool programClassPool,
                                          ClassPool libraryClassPool)
     {
-        this(programClassPool, libraryClassPool, true, true);
+        this(programClassPool, libraryClassPool, true);
     }
 
 
@@ -86,15 +84,11 @@ public class ClassFileReferenceInitializer
      */
     public ClassFileReferenceInitializer(ClassPool programClassPool,
                                          ClassPool libraryClassPool,
-                                         boolean   warn,
-                                         boolean   note)
+                                         boolean   warn)
     {
         this.programClassPool = programClassPool;
         this.libraryClassPool = libraryClassPool;
         this.warn             = warn;
-
-        classFileClassForNameReferenceInitializer =
-            new ClassFileClassForNameReferenceInitializer(programClassPool, note);
     }
 
 
@@ -108,16 +102,6 @@ public class ClassFileReferenceInitializer
     }
 
 
-    /**
-     * Returns the number of notes printed about occurrences of
-     * '<code>(SomeClass)Class.forName(variable).newInstance()</code>'.
-     */
-    public int getNoteCount()
-    {
-        return classFileClassForNameReferenceInitializer.getNoteCount();
-    }
-
-
     // Implementations for ClassFileVisitor.
 
     public void visitProgramClassFile(ProgramClassFile programClassFile)
@@ -136,6 +120,9 @@ public class ClassFileReferenceInitializer
 
     public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
     {
+        // Initialize all fields and methods.
+        libraryClassFile.fieldsAccept(this);
+        libraryClassFile.methodsAccept(this);
     }
 
 
@@ -143,28 +130,36 @@ public class ClassFileReferenceInitializer
 
     public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
     {
-        visitMemberInfo(programClassFile, programFieldInfo);
+        programFieldInfo.referencedClassFile =
+            findReferencedClass(programFieldInfo.getDescriptor(programClassFile));
+
+        // Initialize the attributes.
+        programFieldInfo.attributesAccept(programClassFile, this);
     }
 
 
     public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
-        visitMemberInfo(programClassFile, programMethodInfo);
+        programMethodInfo.referencedClassFiles =
+            findReferencedClasses(programMethodInfo.getDescriptor(programClassFile));
+
+        // Initialize the attributes.
+        programMethodInfo.attributesAccept(programClassFile, this);
     }
 
 
-    private void visitMemberInfo(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
     {
-        programMemberInfo.referencedClassFiles =
-            findReferencedClasses(programMemberInfo.getDescriptor(programClassFile));
-
-        // Initialize the attributes.
-        programMemberInfo.attributesAccept(programClassFile, this);
+        libraryFieldInfo.referencedClassFile =
+            findReferencedClass(libraryFieldInfo.getDescriptor(libraryClassFile));
     }
 
 
-    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
-    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+    {
+        libraryMethodInfo.referencedClassFiles =
+            findReferencedClasses(libraryMethodInfo.getDescriptor(libraryClassFile));
+    }
 
 
     // Implementations for CpInfoVisitor.
@@ -175,6 +170,7 @@ public class ClassFileReferenceInitializer
     public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
     public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
     public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+    public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
 
 
     public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
@@ -209,7 +205,7 @@ public class ClassFileReferenceInitializer
             String name = refCpInfo.getName(classFile);
             String type = refCpInfo.getType(classFile);
 
-            // See if we can find the referenced class membver somewhere in the
+            // See if we can find the referenced class member somewhere in the
             // hierarchy.
             refCpInfo.referencedMemberInfo = memberFinder.findMember(referencedClassFile,
                                                                      name,
@@ -241,13 +237,6 @@ public class ClassFileReferenceInitializer
     }
 
 
-    public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
-    {
-        nameAndTypeCpInfo.referencedClassFiles =
-            findReferencedClasses(nameAndTypeCpInfo.getType(classFile));
-    }
-
-
     // Implementations for AttrInfoVisitor.
 
     public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
@@ -255,8 +244,6 @@ public class ClassFileReferenceInitializer
     public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
     public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
     public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
-    public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
-    public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
     public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
     public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
     public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
@@ -322,7 +309,22 @@ public class ClassFileReferenceInitializer
 
     public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
     {
-        codeAttrInfo.instructionsAccept(classFile, methodInfo, classFileClassForNameReferenceInitializer);
+        // Initialize the nested attributes.
+        codeAttrInfo.attributesAccept(classFile, methodInfo, this);
+    }
+
+
+    public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo)
+    {
+        // Initialize the local variables.
+        localVariableTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
+    }
+
+
+    public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo)
+    {
+        // Initialize the local variable types.
+        localVariableTypeTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
     }
 
 
@@ -373,7 +375,7 @@ public class ClassFileReferenceInitializer
     public void visitLocalVariableInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableInfo localVariableInfo)
     {
         localVariableInfo.referencedClassFile =
-            findClass(classFile.getCpString(localVariableInfo.u2descriptorIndex));
+            findReferencedClass(classFile.getCpString(localVariableInfo.u2descriptorIndex));
     }
 
 
@@ -455,7 +457,7 @@ public class ClassFileReferenceInitializer
             // See if we can find the method in the referenced class
             // (ignoring the descriptor).
             String name = classFile.getCpString(elementValue.u2elementName);
-            
+
             elementValue.referencedMethodInfo =
                 annotation.referencedClassFiles[0].findMethod(name, null);
         }
@@ -465,6 +467,24 @@ public class ClassFileReferenceInitializer
     // Small utility methods.
 
     /**
+     * Returns the single class file referenced by the given descriptor, or
+     * <code>null</code> if there isn't any useful reference.
+     */
+    private ClassFile findReferencedClass(String descriptor)
+    {
+        DescriptorClassEnumeration enumeration =
+            new DescriptorClassEnumeration(descriptor);
+
+        if (enumeration.hasMoreClassNames())
+        {
+            return findClass(enumeration.nextClassName());
+        }
+
+        return null;
+    }
+
+
+    /**
      * Returns an array of class files referenced by the given descriptor, or
      * <code>null</code> if there aren't any useful references.
      */
diff --git a/src/proguard/classfile/util/ClassForNameChecker.java b/src/proguard/classfile/util/ClassForNameChecker.java
index 83885b3..2c9beea 100644
--- a/src/proguard/classfile/util/ClassForNameChecker.java
+++ b/src/proguard/classfile/util/ClassForNameChecker.java
@@ -1,8 +1,8 @@
-/* $Id: ClassForNameChecker.java,v 1.11 2004/12/11 16:35:23 eric Exp $
+/* $Id: ClassForNameChecker.java,v 1.12 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/util/ClassNewInstanceChecker.java b/src/proguard/classfile/util/ClassNewInstanceChecker.java
index d1ffe43..1ccb9b7 100644
--- a/src/proguard/classfile/util/ClassNewInstanceChecker.java
+++ b/src/proguard/classfile/util/ClassNewInstanceChecker.java
@@ -1,8 +1,8 @@
-/* $Id: ClassNewInstanceChecker.java,v 1.7 2004/12/11 16:35:23 eric Exp $
+/* $Id: ClassNewInstanceChecker.java,v 1.8 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/util/ClassUtil.java b/src/proguard/classfile/util/ClassUtil.java
index 2367075..dc372ce 100644
--- a/src/proguard/classfile/util/ClassUtil.java
+++ b/src/proguard/classfile/util/ClassUtil.java
@@ -1,8 +1,8 @@
-/* $Id: ClassUtil.java,v 1.21 2004/08/15 12:39:30 eric Exp $
+/* $Id: ClassUtil.java,v 1.25 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -190,6 +190,21 @@ public class ClassUtil
 
 
     /**
+     * Returns whether the given internal type is a primitive Category 2 type.
+     * @param internalType the internal type,
+     *                     e.g. "<code>L</code>".
+     * @return <code>true</code> if the given type is a Category 2 type,
+     *         <code>false</code> otherwise.
+     */
+    public static boolean isInternalCategory2Type(String internalType)
+    {
+        return internalType.length() == 1 &&
+               (internalType.charAt(0) == ClassConstants.INTERNAL_TYPE_LONG ||
+                internalType.charAt(0) == ClassConstants.INTERNAL_TYPE_DOUBLE);
+    }
+
+
+    /**
      * Returns whether the given internal type is a plain class type
      * (not an array type).
      * @param internalType the internal type,
@@ -236,14 +251,14 @@ public class ClassUtil
 
 
     /**
-     * Returns the internal class name of any given internal type.
-     * The returned class name for primitive array types is
-     * "<code>java/lang/Object</code>".
+     * Returns the internal class name of any given internal type, disregarding
+     * array prefixes.
      * @param internalClassType the internal class type,
      *                          e.g. "<code>Ljava/lang/Object;</code>" or
      *                               "<code>[[I</code>".
      * @return the internal class name,
-     *                          e.g. "<code>java/lang/Object</code>".
+     *                          e.g. "<code>java/lang/Object</code>" or
+     *                               <code>null</code>.
      */
     public static String internalClassNameFromType(String internalClassType)
     {
@@ -259,7 +274,7 @@ public class ClassUtil
             }
             else
             {
-                internalClassType = ClassConstants.INTERNAL_NAME_JAVA_LANG_OBJECT;
+                internalClassType = null;//ClassConstants.INTERNAL_NAME_JAVA_LANG_OBJECT;
             }
         }
 
@@ -480,6 +495,8 @@ public class ClassUtil
                                 ClassConstants.EXTERNAL_TYPE_LONG        :
             internalTypeChar == ClassConstants.INTERNAL_TYPE_DOUBLE      ?
                                 ClassConstants.EXTERNAL_TYPE_DOUBLE      :
+            internalTypeChar == '%'                                      ?
+                                "%"                                      :
             internalTypeChar == ClassConstants.INTERNAL_TYPE_CLASS_START ?
                                 externalClassName(internalType.substring(1, internalType.indexOf(ClassConstants.INTERNAL_TYPE_CLASS_END))) :
                                 null;
diff --git a/src/proguard/classfile/util/DescriptorClassEnumeration.java b/src/proguard/classfile/util/DescriptorClassEnumeration.java
index b0055fd..c92fb13 100644
--- a/src/proguard/classfile/util/DescriptorClassEnumeration.java
+++ b/src/proguard/classfile/util/DescriptorClassEnumeration.java
@@ -1,8 +1,8 @@
-/* $Id: DescriptorClassEnumeration.java,v 1.10 2004/11/26 22:53:15 eric Exp $
+/* $Id: DescriptorClassEnumeration.java,v 1.12 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -74,12 +74,12 @@ public class DescriptorClassEnumeration
         while (nextClassNameStartIndex() >= 0)
         {
             count++;
-            
+
             nextClassNameEndIndex();
         }
 
         index = 0;
-        
+
         return count;
     }
 
@@ -109,19 +109,19 @@ public class DescriptorClassEnumeration
     {
         int classNameStartIndex = nextClassNameStartIndex() + 1;
         int classNameEndIndex   = nextClassNameEndIndex();
-        
+
         return descriptor.substring(classNameStartIndex, classNameEndIndex);
     }
-    
-    
+
+
     private int nextClassNameStartIndex()
     {
         index = descriptor.indexOf(ClassConstants.INTERNAL_TYPE_CLASS_START, index);
-        
+
         return index;
     }
-    
-    
+
+
     private int nextClassNameEndIndex()
     {
         while (++index < descriptor.length())
@@ -133,7 +133,7 @@ public class DescriptorClassEnumeration
                 return index;
             }
         }
-        
+
         throw new IllegalArgumentException("Missing class name terminator in descriptor ["+descriptor+"]");
     }
 
diff --git a/src/proguard/classfile/util/ExternalTypeEnumeration.java b/src/proguard/classfile/util/ExternalTypeEnumeration.java
index c1648db..4631b1f 100644
--- a/src/proguard/classfile/util/ExternalTypeEnumeration.java
+++ b/src/proguard/classfile/util/ExternalTypeEnumeration.java
@@ -1,8 +1,8 @@
-/* $Id: ExternalTypeEnumeration.java,v 1.9 2004/08/15 12:39:30 eric Exp $
+/* $Id: ExternalTypeEnumeration.java,v 1.10 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/util/InternalTypeEnumeration.java b/src/proguard/classfile/util/InternalTypeEnumeration.java
index f60b5b6..d32f6ea 100644
--- a/src/proguard/classfile/util/InternalTypeEnumeration.java
+++ b/src/proguard/classfile/util/InternalTypeEnumeration.java
@@ -1,8 +1,8 @@
-/* $Id: InternalTypeEnumeration.java,v 1.8 2004/08/15 12:39:30 eric Exp $
+/* $Id: InternalTypeEnumeration.java,v 1.9 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/util/MemberFinder.java b/src/proguard/classfile/util/MemberFinder.java
index 27b6451..8294133 100644
--- a/src/proguard/classfile/util/MemberFinder.java
+++ b/src/proguard/classfile/util/MemberFinder.java
@@ -1,8 +1,8 @@
-/* $Id: MemberFinder.java,v 1.4 2004/12/18 20:22:42 eric Exp $
+/* $Id: MemberFinder.java,v 1.7 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -21,8 +21,6 @@
 package proguard.classfile.util;
 
 import proguard.classfile.*;
-import proguard.classfile.attribute.*;
-import proguard.classfile.attribute.annotation.*;
 import proguard.classfile.visitor.*;
 
 
@@ -51,7 +49,7 @@ public class MemberFinder
         return (FieldInfo)findMember(classFile, name, descriptor, true);
     }
 
-    
+
     /**
      * Finds the method with the given name and descriptor in the given
      * class file or its hierarchy.
@@ -60,8 +58,8 @@ public class MemberFinder
     {
         return (MethodInfo)findMember(classFile, name, descriptor, false);
     }
-    
-    
+
+
     /**
      * Finds the class member with the given name and descriptor in the given
      * class file or its hierarchy.
@@ -98,11 +96,11 @@ public class MemberFinder
             {
             }
         }
-        
+
         return memberInfo;
     }
 
-    
+
     /**
      * Returns the corresponding class file of the most recently found class
      * member.
@@ -111,8 +109,8 @@ public class MemberFinder
     {
         return classFile;
     }
-    
-    
+
+
     /**
      * Returns whether the given method is overridden anywhere down the class
      * hierarchy.
@@ -177,14 +175,14 @@ public class MemberFinder
 //    {
 //        visitClassFile(programClassFile);
 //    }
-//    
-//    
+//
+//
 //    public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
 //    {
 //        visitClassFile(libraryClassFile);
 //    }
-//    
-//    
+//
+//
 //    private void visitClassFile(ClassFile classFile)
 //    {
 //        if (memberInfo == null)
@@ -192,15 +190,15 @@ public class MemberFinder
 //            memberInfo = isField ?
 //                (MemberInfo)classFile.findField(name, descriptor) :
 //                (MemberInfo)classFile.findMethod(name, descriptor);
-//                
+//
 //            if (memberInfo != null)
 //            {
 //                this.classFile = classFile;
 //            }
 //        }
 //    }
-    
-    
+
+
     // Implementations for MemberInfoVisitor.
 
     public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
@@ -230,7 +228,7 @@ public class MemberFinder
     {
         this.classFile  = classFile;
         this.memberInfo = memberInfo;
-        
+
         throw MEMBER_FOUND;
     }
 }
diff --git a/src/proguard/obfuscate/MemberInfoLinker.java b/src/proguard/classfile/util/MethodInfoLinker.java
similarity index 65%
rename from src/proguard/obfuscate/MemberInfoLinker.java
rename to src/proguard/classfile/util/MethodInfoLinker.java
index 6afe6a0..dcfe3b8 100644
--- a/src/proguard/obfuscate/MemberInfoLinker.java
+++ b/src/proguard/classfile/util/MethodInfoLinker.java
@@ -1,8 +1,8 @@
-/* $Id: MemberInfoLinker.java,v 1.9 2004/11/20 15:41:24 eric Exp $
+/* $Id: MethodInfoLinker.java,v 1.2 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -18,28 +18,24 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-package proguard.obfuscate;
+package proguard.classfile.util;
 
 import proguard.classfile.*;
 import proguard.classfile.visitor.*;
 
 import java.util.*;
 
-
 /**
- * This ClassFileVisitor links all methods that should get the same names
- * in the name spaces of all visited class files. A class file's name space
- * encompasses all of its subclasses and interfaces. It is typically a class file
- * that is not being subclassed. Chains of links that have been created in
+ * This ClassFileVisitor links all corresponding methods in the class hierarchies
+ * of all visited class files. Visited class files are typically all class
+ * files that are not being subclassed. Chains of links that have been created in
  * previous invocations are merged with new chains of links, in order to create
  * a consistent set of chains. Class initialization methods and constructors are
  * ignored.
  *
- * @see MemberInfoObfuscator
- *
  * @author Eric Lafortune
  */
-public class MemberInfoLinker
+public class MethodInfoLinker
   implements ClassFileVisitor,
              MemberInfoVisitor
 {
@@ -52,11 +48,11 @@ public class MemberInfoLinker
 
     public void visitProgramClassFile(ProgramClassFile programClassFile)
     {
-        // Collect all members in this class's name space.
+        // Collect all members in this class hierarchy.
         programClassFile.hierarchyAccept(true, true, true, false,
                                          new AllMemberInfoVisitor(this));
 
-        // Clean up for obfuscation of the next name space.
+        // Clean up for the next class hierarchy.
         methodInfoMap.clear();
     }
 
@@ -117,7 +113,7 @@ public class MemberInfoLinker
         }
 
         // Get the last method in the chain.
-        MemberInfo thisLastMemberInfo = lastMemberInfo(methodInfo);
+        MemberInfo thisLastMethodInfo = lastMethodInfo(methodInfo);
 
         // See if we've already come across a method with the same name and
         // descriptor.
@@ -127,37 +123,24 @@ public class MemberInfoLinker
         if (otherMethodInfo == null)
         {
             // Store the new class method info in the map.
-            methodInfoMap.put(key, thisLastMemberInfo);
+            methodInfoMap.put(key, thisLastMethodInfo);
         }
         else
         {
             // Get the last method in the other chain.
-            MemberInfo otherLastMemberInfo = lastMemberInfo(otherMethodInfo);
+            MethodInfo otherLastMethodInfo = lastMethodInfo(otherMethodInfo);
 
             // Check if both link chains aren't already ending in the same element.
-            if (thisLastMemberInfo != otherLastMemberInfo)
+            if (!thisLastMethodInfo.equals(otherLastMethodInfo))
             {
-                // Merge the two chains, making sure LibraryMethodInfo elements,
-                // if any, are at the end of the resulting chain.
-                if (thisLastMemberInfo instanceof LibraryMethodInfo)
-                {
-                    // This class method chain ends with a library class method.
-                    // Link this chain to the end of the other one.
-                    otherLastMemberInfo.setVisitorInfo(thisLastMemberInfo);
-                }
-                /* We can skip this test and go straight to the final case.
-                else if (otherLastVisitorAccepter instanceof LibraryMethodInfo)
+                // Merge the two chains, with the library members last.
+                if (otherLastMethodInfo instanceof LibraryMemberInfo)
                 {
-                    // The other method chain ends with a library class method.
-                    // Link the other chain to the end of this one.
-                    thisLastVisitorAccepter.setVisitorInfo(otherLastVisitorAccepter);
+                    thisLastMethodInfo.setVisitorInfo(otherLastMethodInfo);
                 }
-                */
                 else
                 {
-                    // We have two non-library methods. Link their chains
-                    // one way or another.
-                    thisLastMemberInfo.setVisitorInfo(otherLastMemberInfo);
+                    otherLastMethodInfo.setVisitorInfo(thisLastMethodInfo);
                 }
             }
         }
@@ -167,19 +150,36 @@ public class MemberInfoLinker
     // Small utility methods.
 
     /**
-     * Finds the last class member in the linked list of class members.
-     * @param memberInfo the given class member.
-     * @return the last class member in the linked list.
+     * Finds the last method in the linked list of related methods.
+     * @param methodInfo the given method.
+     * @return the last method in the linked list.
+     */
+    public static MethodInfo lastMethodInfo(MethodInfo methodInfo)
+    {
+        MethodInfo lastMethodInfo = methodInfo;
+        while (lastMethodInfo.getVisitorInfo() != null &&
+               lastMethodInfo.getVisitorInfo() instanceof MethodInfo)
+        {
+            lastMethodInfo = (MethodInfo)lastMethodInfo.getVisitorInfo();
+        }
+
+        return lastMethodInfo;
+    }
+
+    /**
+     * Finds the last visitor accepter in the linked list of visitors.
+     * @param visitorAccepter the given method.
+     * @return the last method in the linked list.
      */
-    static MemberInfo lastMemberInfo(MemberInfo memberInfo)
+    public static VisitorAccepter lastVisitorAccepter(VisitorAccepter visitorAccepter)
     {
-        VisitorAccepter lastVisitorAccepter = memberInfo;
+        VisitorAccepter lastVisitorAccepter = visitorAccepter;
         while (lastVisitorAccepter.getVisitorInfo() != null &&
                lastVisitorAccepter.getVisitorInfo() instanceof VisitorAccepter)
         {
             lastVisitorAccepter = (VisitorAccepter)lastVisitorAccepter.getVisitorInfo();
         }
 
-        return (MemberInfo)lastVisitorAccepter;
+        return lastVisitorAccepter;
     }
 }
diff --git a/src/proguard/classfile/visitor/AllClassFileVisitor.java b/src/proguard/classfile/visitor/AllClassFileVisitor.java
index 64e28f6..25ab8aa 100644
--- a/src/proguard/classfile/visitor/AllClassFileVisitor.java
+++ b/src/proguard/classfile/visitor/AllClassFileVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: AllClassFileVisitor.java,v 1.10 2004/08/15 12:39:30 eric Exp $
+/* $Id: AllClassFileVisitor.java,v 1.11 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/AllCpInfoVisitor.java b/src/proguard/classfile/visitor/AllCpInfoVisitor.java
index d23a284..480ba39 100644
--- a/src/proguard/classfile/visitor/AllCpInfoVisitor.java
+++ b/src/proguard/classfile/visitor/AllCpInfoVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: AllCpInfoVisitor.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: AllCpInfoVisitor.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/AllFieldVisitor.java b/src/proguard/classfile/visitor/AllFieldVisitor.java
index ac23349..4be2777 100644
--- a/src/proguard/classfile/visitor/AllFieldVisitor.java
+++ b/src/proguard/classfile/visitor/AllFieldVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: AllFieldVisitor.java,v 1.12 2004/08/15 12:39:30 eric Exp $
+/* $Id: AllFieldVisitor.java,v 1.13 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/AllMemberInfoVisitor.java b/src/proguard/classfile/visitor/AllMemberInfoVisitor.java
index e24d744..2301cb4 100644
--- a/src/proguard/classfile/visitor/AllMemberInfoVisitor.java
+++ b/src/proguard/classfile/visitor/AllMemberInfoVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: AllMemberInfoVisitor.java,v 1.10 2004/08/15 12:39:30 eric Exp $
+/* $Id: AllMemberInfoVisitor.java,v 1.11 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/AllMethodVisitor.java b/src/proguard/classfile/visitor/AllMethodVisitor.java
index e259ee4..b1f82fc 100644
--- a/src/proguard/classfile/visitor/AllMethodVisitor.java
+++ b/src/proguard/classfile/visitor/AllMethodVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: AllMethodVisitor.java,v 1.12 2004/08/15 12:39:30 eric Exp $
+/* $Id: AllMethodVisitor.java,v 1.13 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/BottomClassFileFilter.java b/src/proguard/classfile/visitor/BottomClassFileFilter.java
index 2af242a..9876961 100644
--- a/src/proguard/classfile/visitor/BottomClassFileFilter.java
+++ b/src/proguard/classfile/visitor/BottomClassFileFilter.java
@@ -1,8 +1,8 @@
-/* $Id: BottomClassFileFilter.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+/* $Id: BottomClassFileFilter.java,v 1.6 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassFileAccessFilter.java b/src/proguard/classfile/visitor/ClassFileAccessFilter.java
index 35848c1..18c7777 100644
--- a/src/proguard/classfile/visitor/ClassFileAccessFilter.java
+++ b/src/proguard/classfile/visitor/ClassFileAccessFilter.java
@@ -1,8 +1,8 @@
-/* $Id: ClassFileAccessFilter.java,v 1.6 2004/12/11 16:35:23 eric Exp $
+/* $Id: ClassFileAccessFilter.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassFileCleaner.java b/src/proguard/classfile/visitor/ClassFileCleaner.java
index a80348e..ec90a32 100644
--- a/src/proguard/classfile/visitor/ClassFileCleaner.java
+++ b/src/proguard/classfile/visitor/ClassFileCleaner.java
@@ -1,8 +1,8 @@
-/* $Id: ClassFileCleaner.java,v 1.17 2004/11/20 15:41:24 eric Exp $
+/* $Id: ClassFileCleaner.java,v 1.18 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassFileHierarchyTraveler.java b/src/proguard/classfile/visitor/ClassFileHierarchyTraveler.java
index c263058..2fe7d36 100644
--- a/src/proguard/classfile/visitor/ClassFileHierarchyTraveler.java
+++ b/src/proguard/classfile/visitor/ClassFileHierarchyTraveler.java
@@ -1,8 +1,8 @@
-/* $Id: ClassFileHierarchyTraveler.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: ClassFileHierarchyTraveler.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassFileMemberInfoVisitor.java b/src/proguard/classfile/visitor/ClassFileMemberInfoVisitor.java
index 19fd93a..25637b9 100644
--- a/src/proguard/classfile/visitor/ClassFileMemberInfoVisitor.java
+++ b/src/proguard/classfile/visitor/ClassFileMemberInfoVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: ClassFileMemberInfoVisitor.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+/* $Id: ClassFileMemberInfoVisitor.java,v 1.5 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassFileNameFilter.java b/src/proguard/classfile/visitor/ClassFileNameFilter.java
index 96e8e17..cb1a026 100644
--- a/src/proguard/classfile/visitor/ClassFileNameFilter.java
+++ b/src/proguard/classfile/visitor/ClassFileNameFilter.java
@@ -1,8 +1,8 @@
-/* $Id: ClassFileNameFilter.java,v 1.8 2004/08/15 12:39:30 eric Exp $
+/* $Id: ClassFileNameFilter.java,v 1.9 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassFilePrinter.java b/src/proguard/classfile/visitor/ClassFilePrinter.java
index 8d1268b..14f33f0 100644
--- a/src/proguard/classfile/visitor/ClassFilePrinter.java
+++ b/src/proguard/classfile/visitor/ClassFilePrinter.java
@@ -1,8 +1,8 @@
-/* $Id: ClassFilePrinter.java,v 1.30 2004/12/11 16:35:23 eric Exp $
+/* $Id: ClassFilePrinter.java,v 1.31 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassFileVisitor.java b/src/proguard/classfile/visitor/ClassFileVisitor.java
index 7723f7a..91b8867 100644
--- a/src/proguard/classfile/visitor/ClassFileVisitor.java
+++ b/src/proguard/classfile/visitor/ClassFileVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: ClassFileVisitor.java,v 1.7 2004/08/15 12:39:30 eric Exp $
+/* $Id: ClassFileVisitor.java,v 1.8 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassPoolFiller.java b/src/proguard/classfile/visitor/ClassPoolFiller.java
index 19ac0c9..eda6aeb 100644
--- a/src/proguard/classfile/visitor/ClassPoolFiller.java
+++ b/src/proguard/classfile/visitor/ClassPoolFiller.java
@@ -1,8 +1,8 @@
-/* $Id: ClassPoolFiller.java,v 1.8 2004/08/15 12:39:30 eric Exp $
+/* $Id: ClassPoolFiller.java,v 1.9 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ClassPoolVisitor.java b/src/proguard/classfile/visitor/ClassPoolVisitor.java
index 111c6d9..8b00c02 100644
--- a/src/proguard/classfile/visitor/ClassPoolVisitor.java
+++ b/src/proguard/classfile/visitor/ClassPoolVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: ClassPoolVisitor.java,v 1.9 2004/08/15 12:39:30 eric Exp $
+/* $Id: ClassPoolVisitor.java,v 1.10 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ConcreteClassFileDownTraveler.java b/src/proguard/classfile/visitor/ConcreteClassFileDownTraveler.java
index bba9771..331367f 100644
--- a/src/proguard/classfile/visitor/ConcreteClassFileDownTraveler.java
+++ b/src/proguard/classfile/visitor/ConcreteClassFileDownTraveler.java
@@ -1,8 +1,8 @@
-/* $Id: ConcreteClassFileDownTraveler.java,v 1.7 2004/08/15 12:39:30 eric Exp $
+/* $Id: ConcreteClassFileDownTraveler.java,v 1.8 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/CpInfoVisitor.java b/src/proguard/classfile/visitor/CpInfoVisitor.java
index c4b190b..17b6ee6 100644
--- a/src/proguard/classfile/visitor/CpInfoVisitor.java
+++ b/src/proguard/classfile/visitor/CpInfoVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: CpInfoVisitor.java,v 1.7 2004/08/15 12:39:30 eric Exp $
+/* $Id: CpInfoVisitor.java,v 1.8 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/LibraryClassFileFilter.java b/src/proguard/classfile/visitor/LibraryClassFileFilter.java
index 203dd17..9da5cdb 100644
--- a/src/proguard/classfile/visitor/LibraryClassFileFilter.java
+++ b/src/proguard/classfile/visitor/LibraryClassFileFilter.java
@@ -1,8 +1,8 @@
-/* $Id: LibraryClassFileFilter.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: LibraryClassFileFilter.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/LibraryMemberInfoFilter.java b/src/proguard/classfile/visitor/LibraryMemberInfoFilter.java
index 9d32e2e..dd32a42 100644
--- a/src/proguard/classfile/visitor/LibraryMemberInfoFilter.java
+++ b/src/proguard/classfile/visitor/LibraryMemberInfoFilter.java
@@ -1,8 +1,8 @@
-/* $Id: LibraryMemberInfoFilter.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+/* $Id: LibraryMemberInfoFilter.java,v 1.5 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/LineNumberInfoVisitor.java b/src/proguard/classfile/visitor/LineNumberInfoVisitor.java
index 61a2083..770390a 100644
--- a/src/proguard/classfile/visitor/LineNumberInfoVisitor.java
+++ b/src/proguard/classfile/visitor/LineNumberInfoVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: LineNumberInfoVisitor.java,v 1.9 2004/10/10 20:56:58 eric Exp $
+/* $Id: LineNumberInfoVisitor.java,v 1.10 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/MemberInfoAccessFilter.java b/src/proguard/classfile/visitor/MemberInfoAccessFilter.java
index 0c8ac62..8b89470 100644
--- a/src/proguard/classfile/visitor/MemberInfoAccessFilter.java
+++ b/src/proguard/classfile/visitor/MemberInfoAccessFilter.java
@@ -1,8 +1,8 @@
-/* $Id: MemberInfoAccessFilter.java,v 1.6 2004/12/11 16:35:23 eric Exp $
+/* $Id: MemberInfoAccessFilter.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/MemberInfoDescriptorFilter.java b/src/proguard/classfile/visitor/MemberInfoDescriptorFilter.java
index 3475e46..4c0e37c 100644
--- a/src/proguard/classfile/visitor/MemberInfoDescriptorFilter.java
+++ b/src/proguard/classfile/visitor/MemberInfoDescriptorFilter.java
@@ -1,8 +1,8 @@
-/* $Id: MemberInfoDescriptorFilter.java,v 1.9 2004/11/27 10:09:26 eric Exp $
+/* $Id: MemberInfoDescriptorFilter.java,v 1.10 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/MemberInfoNameFilter.java b/src/proguard/classfile/visitor/MemberInfoNameFilter.java
index 1da77ed..8e1daaa 100644
--- a/src/proguard/classfile/visitor/MemberInfoNameFilter.java
+++ b/src/proguard/classfile/visitor/MemberInfoNameFilter.java
@@ -1,8 +1,8 @@
-/* $Id: MemberInfoNameFilter.java,v 1.9 2004/11/27 10:09:26 eric Exp $
+/* $Id: MemberInfoNameFilter.java,v 1.10 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/MemberInfoVisitor.java b/src/proguard/classfile/visitor/MemberInfoVisitor.java
index 1a36ebd..c178174 100644
--- a/src/proguard/classfile/visitor/MemberInfoVisitor.java
+++ b/src/proguard/classfile/visitor/MemberInfoVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: MemberInfoVisitor.java,v 1.10 2004/08/15 12:39:30 eric Exp $
+/* $Id: MemberInfoVisitor.java,v 1.11 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ProgramMemberInfoFilter.java b/src/proguard/classfile/visitor/MethodImplementationFilter.java
similarity index 60%
copy from src/proguard/classfile/visitor/ProgramMemberInfoFilter.java
copy to src/proguard/classfile/visitor/MethodImplementationFilter.java
index 82a9cb5..7660040 100644
--- a/src/proguard/classfile/visitor/ProgramMemberInfoFilter.java
+++ b/src/proguard/classfile/visitor/MethodImplementationFilter.java
@@ -1,8 +1,8 @@
-/* $Id: ProgramMemberInfoFilter.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+/* $Id: MethodImplementationFilter.java,v 1.3 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -24,23 +24,25 @@ import proguard.classfile.*;
 
 
 /**
- * This <code>MemberInfoVisitor</code> delegates its visits to another given
- * <code>MemberInfoVisitor</code>, but only when visiting members of program
- * class files.
+ * This <code>MemberInfoVisitor</code> delegates its visits to methods to
+ * another given <code>MemberInfoVisitor</code>, but only when the visited
+ * method may have implementations.
  *
+ * @see ClassFile#mayHaveImplementations(MethodInfo)
  * @author Eric Lafortune
  */
-public class ProgramMemberInfoFilter implements MemberInfoVisitor
+public class MethodImplementationFilter
+  implements MemberInfoVisitor
 {
     private MemberInfoVisitor memberInfoVisitor;
 
 
     /**
-     * Creates a new ProgramMemberInfoFilter.
+     * Creates a new MethodImplementationFilter.
      * @param memberInfoVisitor the <code>MemberInfoVisitor</code> to which
      *                          visits will be delegated.
      */
-    public ProgramMemberInfoFilter(MemberInfoVisitor memberInfoVisitor)
+    public MethodImplementationFilter(MemberInfoVisitor memberInfoVisitor)
     {
         this.memberInfoVisitor = memberInfoVisitor;
     }
@@ -48,26 +50,26 @@ public class ProgramMemberInfoFilter implements MemberInfoVisitor
 
     // Implementations for MemberInfoVisitor.
 
-    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
-    {
-        memberInfoVisitor.visitProgramFieldInfo(programClassFile, programFieldInfo);
-    }
+    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
 
 
     public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
-        memberInfoVisitor.visitProgramMethodInfo(programClassFile, programMethodInfo);
+        if (programClassFile.mayHaveImplementations(programMethodInfo))
+        {
+            memberInfoVisitor.visitProgramMethodInfo(programClassFile, programMethodInfo);
+        }
     }
 
 
-    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
-    {
-        // Don't delegate visits to library members.
-    }
+    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
 
 
     public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
     {
-        // Don't delegate visits to library members.
+        if (libraryClassFile.mayHaveImplementations(libraryMethodInfo))
+        {
+            memberInfoVisitor.visitLibraryMethodInfo(libraryClassFile, libraryMethodInfo);
+        }
     }
 }
diff --git a/src/proguard/classfile/visitor/LibraryMemberInfoFilter.java b/src/proguard/classfile/visitor/MethodImplementationTraveler.java
similarity index 54%
copy from src/proguard/classfile/visitor/LibraryMemberInfoFilter.java
copy to src/proguard/classfile/visitor/MethodImplementationTraveler.java
index 9d32e2e..f881fde 100644
--- a/src/proguard/classfile/visitor/LibraryMemberInfoFilter.java
+++ b/src/proguard/classfile/visitor/MethodImplementationTraveler.java
@@ -1,8 +1,8 @@
-/* $Id: LibraryMemberInfoFilter.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+/* $Id: MethodImplementationTraveler.java,v 1.3 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -24,50 +24,54 @@ import proguard.classfile.*;
 
 
 /**
- * This <code>MemberInfoVisitor</code> delegates its visits to another given
- * <code>MemberInfoVisitor</code>, but only when visiting members of library
- * class files.
+ * This <code>MemberInfoVisitor</code> lets a given
+ * <code>MemberInfoVisitor</code> travel to all concrete implementations of
+ * the visited methods in their class hierarchies.
  *
  * @author Eric Lafortune
  */
-public class LibraryMemberInfoFilter implements MemberInfoVisitor
+public class MethodImplementationTraveler
+  implements MemberInfoVisitor
 {
+    private boolean           visitThisMethod;
     private MemberInfoVisitor memberInfoVisitor;
 
 
     /**
-     * Creates a new ProgramMemberInfoFilter.
+     * Creates a new MethodImplementationTraveler.
+     * @param visitThisMethod   specifies whether to visit the originally
+     *                          visited methods.
      * @param memberInfoVisitor the <code>MemberInfoVisitor</code> to which
      *                          visits will be delegated.
      */
-    public LibraryMemberInfoFilter(MemberInfoVisitor memberInfoVisitor)
+    public MethodImplementationTraveler(boolean           visitThisMethod,
+                                        MemberInfoVisitor memberInfoVisitor)
     {
+        this.visitThisMethod   = visitThisMethod;
         this.memberInfoVisitor = memberInfoVisitor;
     }
 
 
     // Implementations for MemberInfoVisitor.
 
-    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
-    {
-        // Don't delegate visits to program members.
-    }
+    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
 
 
     public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
-        // Don't delegate visits to program members.
+        programClassFile.methodImplementationsAccept(programMethodInfo,
+                                                     visitThisMethod,
+                                                     memberInfoVisitor);
     }
 
 
-    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
-    {
-        memberInfoVisitor.visitLibraryFieldInfo(libraryClassFile, libraryFieldInfo);
-    }
+    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
 
 
     public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
     {
-        memberInfoVisitor.visitLibraryMethodInfo(libraryClassFile, libraryMethodInfo);
+        libraryClassFile.methodImplementationsAccept(libraryMethodInfo,
+                                                     visitThisMethod,
+                                                     memberInfoVisitor);
     }
 }
diff --git a/src/proguard/classfile/visitor/MultiClassFileVisitor.java b/src/proguard/classfile/visitor/MultiClassFileVisitor.java
index ac6abc1..2235dd7 100644
--- a/src/proguard/classfile/visitor/MultiClassFileVisitor.java
+++ b/src/proguard/classfile/visitor/MultiClassFileVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: MultiClassFileVisitor.java,v 1.8 2004/08/15 12:39:30 eric Exp $
+/* $Id: MultiClassFileVisitor.java,v 1.9 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/MultiMemberInfoVisitor.java b/src/proguard/classfile/visitor/MultiMemberInfoVisitor.java
index 5f4dda1..812449a 100644
--- a/src/proguard/classfile/visitor/MultiMemberInfoVisitor.java
+++ b/src/proguard/classfile/visitor/MultiMemberInfoVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: MultiMemberInfoVisitor.java,v 1.11 2004/08/15 12:39:30 eric Exp $
+/* $Id: MultiMemberInfoVisitor.java,v 1.12 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/NamedClassFileVisitor.java b/src/proguard/classfile/visitor/NamedClassFileVisitor.java
index 550487c..726034b 100644
--- a/src/proguard/classfile/visitor/NamedClassFileVisitor.java
+++ b/src/proguard/classfile/visitor/NamedClassFileVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: NamedClassFileVisitor.java,v 1.8 2004/08/15 12:39:30 eric Exp $
+/* $Id: NamedClassFileVisitor.java,v 1.9 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/NamedFieldVisitor.java b/src/proguard/classfile/visitor/NamedFieldVisitor.java
index c1884db..4f8e917 100644
--- a/src/proguard/classfile/visitor/NamedFieldVisitor.java
+++ b/src/proguard/classfile/visitor/NamedFieldVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: NamedFieldVisitor.java,v 1.11 2004/12/11 16:35:23 eric Exp $
+/* $Id: NamedFieldVisitor.java,v 1.12 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/NamedMethodVisitor.java b/src/proguard/classfile/visitor/NamedMethodVisitor.java
index fdaed64..8933ba8 100644
--- a/src/proguard/classfile/visitor/NamedMethodVisitor.java
+++ b/src/proguard/classfile/visitor/NamedMethodVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: NamedMethodVisitor.java,v 1.11 2004/12/11 16:35:23 eric Exp $
+/* $Id: NamedMethodVisitor.java,v 1.12 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ProgramClassFileFilter.java b/src/proguard/classfile/visitor/ProgramClassFileFilter.java
index b825e97..69f2fb7 100644
--- a/src/proguard/classfile/visitor/ProgramClassFileFilter.java
+++ b/src/proguard/classfile/visitor/ProgramClassFileFilter.java
@@ -1,8 +1,8 @@
-/* $Id: ProgramClassFileFilter.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: ProgramClassFileFilter.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ProgramMemberInfoFilter.java b/src/proguard/classfile/visitor/ProgramMemberInfoFilter.java
index 82a9cb5..9212352 100644
--- a/src/proguard/classfile/visitor/ProgramMemberInfoFilter.java
+++ b/src/proguard/classfile/visitor/ProgramMemberInfoFilter.java
@@ -1,8 +1,8 @@
-/* $Id: ProgramMemberInfoFilter.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+/* $Id: ProgramMemberInfoFilter.java,v 1.5 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/ReferencedClassFileVisitor.java b/src/proguard/classfile/visitor/ReferencedClassFileVisitor.java
index 12a89e5..95edea9 100644
--- a/src/proguard/classfile/visitor/ReferencedClassFileVisitor.java
+++ b/src/proguard/classfile/visitor/ReferencedClassFileVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: ReferencedClassFileVisitor.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+/* $Id: ReferencedClassFileVisitor.java,v 1.6 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -48,6 +48,7 @@ public class ReferencedClassFileVisitor
     public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
     public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
     public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+    public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
 
 
     public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
@@ -80,12 +81,6 @@ public class ReferencedClassFileVisitor
     }
 
 
-    public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
-    {
-        visitReferencedClassFiles(nameAndTypeCpInfo.referencedClassFiles);
-    }
-
-
     // Small utility methods.
 
     private void visitReferencedClassFiles(ClassFile[] referencedClassFiles)
diff --git a/src/proguard/classfile/visitor/SimpleClassFilePrinter.java b/src/proguard/classfile/visitor/SimpleClassFilePrinter.java
index c09ac46..7b7206f 100644
--- a/src/proguard/classfile/visitor/SimpleClassFilePrinter.java
+++ b/src/proguard/classfile/visitor/SimpleClassFilePrinter.java
@@ -1,8 +1,8 @@
-/* $Id: SimpleClassFilePrinter.java,v 1.17 2004/08/15 12:39:30 eric Exp $
+/* $Id: SimpleClassFilePrinter.java,v 1.18 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/VariableClassFileVisitor.java b/src/proguard/classfile/visitor/VariableClassFileVisitor.java
index ab555a8..803136b 100644
--- a/src/proguard/classfile/visitor/VariableClassFileVisitor.java
+++ b/src/proguard/classfile/visitor/VariableClassFileVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: VariableClassFileVisitor.java,v 1.7 2004/08/15 12:39:30 eric Exp $
+/* $Id: VariableClassFileVisitor.java,v 1.8 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/VariableMemberInfoVisitor.java b/src/proguard/classfile/visitor/VariableMemberInfoVisitor.java
index 2fdeef3..a4d716a 100644
--- a/src/proguard/classfile/visitor/VariableMemberInfoVisitor.java
+++ b/src/proguard/classfile/visitor/VariableMemberInfoVisitor.java
@@ -1,8 +1,8 @@
-/* $Id: VariableMemberInfoVisitor.java,v 1.11 2004/08/15 12:39:30 eric Exp $
+/* $Id: VariableMemberInfoVisitor.java,v 1.12 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/ClassMemberSpecificationDialog.java b/src/proguard/gui/ClassMemberSpecificationDialog.java
index 6777bff..25a4bb2 100644
--- a/src/proguard/gui/ClassMemberSpecificationDialog.java
+++ b/src/proguard/gui/ClassMemberSpecificationDialog.java
@@ -1,8 +1,8 @@
-/* $Id: ClassMemberSpecificationDialog.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: ClassMemberSpecificationDialog.java,v 1.4 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -133,7 +133,7 @@ class ClassMemberSpecificationDialog extends JDialog
         okButtonConstraints.insets  = new Insets(4, 4, 8, 4);
 
         GridBagConstraints cancelButtonConstraints = new GridBagConstraints();
-        cancelButtonConstraints.gridwidth = GridBagConstraints.REMAINDER;;
+        cancelButtonConstraints.gridwidth = GridBagConstraints.REMAINDER;
         cancelButtonConstraints.weighty   = 1.0;
         cancelButtonConstraints.anchor    = GridBagConstraints.SOUTHEAST;
         cancelButtonConstraints.insets    = okButtonConstraints.insets;
diff --git a/src/proguard/gui/ClassMemberSpecificationsPanel.java b/src/proguard/gui/ClassMemberSpecificationsPanel.java
index 4d34fed..3964b42 100644
--- a/src/proguard/gui/ClassMemberSpecificationsPanel.java
+++ b/src/proguard/gui/ClassMemberSpecificationsPanel.java
@@ -1,8 +1,8 @@
-/* $Id: ClassMemberSpecificationsPanel.java,v 1.5 2004/08/28 22:50:49 eric Exp $
+/* $Id: ClassMemberSpecificationsPanel.java,v 1.6 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/ClassPathPanel.java b/src/proguard/gui/ClassPathPanel.java
index a15d1f5..aa7ce86 100644
--- a/src/proguard/gui/ClassPathPanel.java
+++ b/src/proguard/gui/ClassPathPanel.java
@@ -1,8 +1,8 @@
-/* $Id: ClassPathPanel.java,v 1.14 2004/08/21 21:35:28 eric Exp $
+/* $Id: ClassPathPanel.java,v 1.16 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -129,7 +129,7 @@ class ClassPathPanel extends ListPanel
 
                     isOutput = entry.isOutput();
 
-                    selectedFiles[index] = new File(entry.getName());
+                    selectedFiles[index] = entry.getFile();
                 }
 
                 chooser.setDialogTitle(GUIResources.getMessage("chooseJars"));
@@ -248,7 +248,7 @@ class ClassPathPanel extends ListPanel
         ClassPathEntry[] entries = new ClassPathEntry[files.length];
         for (int index = 0; index < entries.length; index++)
         {
-            entries[index] = new ClassPathEntry(files[index].toString(), isOutput);
+            entries[index] = new ClassPathEntry(files[index], isOutput);
         }
         return entries;
     }
@@ -381,7 +381,7 @@ class ClassPathPanel extends ListPanel
 
             // Make the font color red if this is an input file that can't be read.
             if (!(inputAndOutput && entry.isOutput()) &&
-                !new File(entry.getName()).canRead())
+                !entry.getFile().canRead())
             {
                 jarNameLabel.setForeground(Color.red);
             }
diff --git a/src/proguard/gui/ClassSpecificationDialog.java b/src/proguard/gui/ClassSpecificationDialog.java
index d98efb8..834b583 100644
--- a/src/proguard/gui/ClassSpecificationDialog.java
+++ b/src/proguard/gui/ClassSpecificationDialog.java
@@ -1,8 +1,8 @@
-/* $Id: ClassSpecificationDialog.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: ClassSpecificationDialog.java,v 1.4 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -131,7 +131,7 @@ class ClassSpecificationDialog extends JDialog
         okButtonConstraints.insets  = new Insets(4, 4, 8, 4);
 
         GridBagConstraints cancelButtonConstraints = new GridBagConstraints();
-        cancelButtonConstraints.gridwidth = GridBagConstraints.REMAINDER;;
+        cancelButtonConstraints.gridwidth = GridBagConstraints.REMAINDER;
         cancelButtonConstraints.weighty   = 1.0;
         cancelButtonConstraints.anchor    = GridBagConstraints.SOUTHEAST;
         cancelButtonConstraints.insets    = okButtonConstraints.insets;
diff --git a/src/proguard/gui/ClassSpecificationsPanel.java b/src/proguard/gui/ClassSpecificationsPanel.java
index 0746ab1..568c486 100644
--- a/src/proguard/gui/ClassSpecificationsPanel.java
+++ b/src/proguard/gui/ClassSpecificationsPanel.java
@@ -1,8 +1,8 @@
-/* $Id: ClassSpecificationsPanel.java,v 1.4 2004/08/28 22:50:49 eric Exp $
+/* $Id: ClassSpecificationsPanel.java,v 1.5 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/ExtensionFileFilter.java b/src/proguard/gui/ExtensionFileFilter.java
index 9a69355..5b8ef1d 100644
--- a/src/proguard/gui/ExtensionFileFilter.java
+++ b/src/proguard/gui/ExtensionFileFilter.java
@@ -1,8 +1,8 @@
-/* $Id: ExtensionFileFilter.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+/* $Id: ExtensionFileFilter.java,v 1.6 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/FilterDialog.java b/src/proguard/gui/FilterDialog.java
index 8d2d791..c92e28b 100644
--- a/src/proguard/gui/FilterDialog.java
+++ b/src/proguard/gui/FilterDialog.java
@@ -1,8 +1,8 @@
-/* $Id: FilterDialog.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: FilterDialog.java,v 1.4 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -100,7 +100,7 @@ public class FilterDialog extends JDialog
         okButtonConstraints.insets  = new Insets(4, 4, 8, 4);
 
         GridBagConstraints cancelButtonConstraints = new GridBagConstraints();
-        cancelButtonConstraints.gridwidth = GridBagConstraints.REMAINDER;;
+        cancelButtonConstraints.gridwidth = GridBagConstraints.REMAINDER;
         cancelButtonConstraints.weighty   = 1.0;
         cancelButtonConstraints.anchor    = GridBagConstraints.SOUTHEAST;
         cancelButtonConstraints.insets    = okButtonConstraints.insets;
diff --git a/src/proguard/gui/GUIResources.java b/src/proguard/gui/GUIResources.java
index fa126d5..8f895f3 100644
--- a/src/proguard/gui/GUIResources.java
+++ b/src/proguard/gui/GUIResources.java
@@ -1,8 +1,8 @@
-/* $Id: GUIResources.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+/* $Id: GUIResources.java,v 1.6 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/GUIResources.properties b/src/proguard/gui/GUIResources.properties
index fe0ca28..9132b6f 100644
--- a/src/proguard/gui/GUIResources.properties
+++ b/src/proguard/gui/GUIResources.properties
@@ -1,5 +1,5 @@
 # ProGuard -- shrinking, optimization, and obfuscation of Java class files.
-# Copyright (c) 1999-2004 Eric Lafortune (eric at graphics.cornell.edu)
+# Copyright (c) 1999-2005 Eric Lafortune (eric at graphics.cornell.edu)
 
 #
 # Tab names.
@@ -24,11 +24,12 @@ obfuscation  = Obfuscation
 #
 # Panel titles.
 #
-welcome                       = Welcome to ProGuard, version 3.2
+welcome                       = Welcome to ProGuard, version 3.3.2
 options                       = Options
 keepAdditional                = Keep additional classes and class members
 keepNamesAdditional           = Keep additional class names and class member names
 assumeNoSideEffectsAdditional = Assume no side effects for additional methods
+whyAreYouKeeping              = Why are you keeping
 consistencyAndCorrectness     = Consistency and correctness
 processingConsole             = Processing console
 reTraceSettings               = ReTrace settings
@@ -56,7 +57,7 @@ proGuardInfo = \
   \n\n\
   Distributed under the GNU General Public License.\
   \n\
-  Copyright (c) 1999-2004.
+  Copyright (c) 1999-2005.
 
 processingInfo = \
   You can now start processing your code, \
diff --git a/src/proguard/gui/ListPanel.java b/src/proguard/gui/ListPanel.java
index 8f2021f..8dffcd1 100644
--- a/src/proguard/gui/ListPanel.java
+++ b/src/proguard/gui/ListPanel.java
@@ -1,8 +1,8 @@
-/* $Id: ListPanel.java,v 1.8 2004/08/15 12:39:30 eric Exp $
+/* $Id: ListPanel.java,v 1.9 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/MessageDialogRunnable.java b/src/proguard/gui/MessageDialogRunnable.java
index c3b6d1c..323a38f 100644
--- a/src/proguard/gui/MessageDialogRunnable.java
+++ b/src/proguard/gui/MessageDialogRunnable.java
@@ -1,8 +1,8 @@
-/* $Id: MessageDialogRunnable.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+/* $Id: MessageDialogRunnable.java,v 1.6 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/ProGuardGUI.java b/src/proguard/gui/ProGuardGUI.java
index d5d9512..7c7465f 100644
--- a/src/proguard/gui/ProGuardGUI.java
+++ b/src/proguard/gui/ProGuardGUI.java
@@ -1,8 +1,8 @@
-/* $Id: ProGuardGUI.java,v 1.27 2004/11/20 15:08:57 eric Exp $
+/* $Id: ProGuardGUI.java,v 1.34 2005/06/25 22:08:57 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -21,10 +21,9 @@
 package proguard.gui;
 
 import proguard.*;
-import proguard.optimize.NoSideEffectMethodMarker;
-import proguard.util.*;
-import proguard.classfile.util.*;
+import proguard.classfile.util.ClassUtil;
 import proguard.gui.splash.*;
+import proguard.util.ListUtil;
 
 import javax.swing.*;
 import javax.swing.border.*;
@@ -81,6 +80,8 @@ public class ProGuardGUI extends JFrame
 
     private ClassSpecificationsPanel additionalNoSideEffectsPanel = new ClassSpecificationsPanel(this, false);
 
+    private ClassSpecificationsPanel whyAreYouKeepingPanel = new ClassSpecificationsPanel(this, false);
+
     private JCheckBox shrinkCheckBox                           = new JCheckBox(msg("shrink"));
     private JCheckBox printUsageCheckBox                       = new JCheckBox(msg("printUsage"));
 
@@ -204,16 +205,18 @@ public class ProGuardGUI extends JFrame
         lastBottomButtonConstraints.ipadx     = bottomButtonConstraints.ipadx;
         lastBottomButtonConstraints.ipady     = bottomButtonConstraints.ipady;
 
+        // Leave room for a growBox on Mac OS X.
+        if (System.getProperty("os.name").toLowerCase().startsWith("mac os x"))
+        {
+            lastBottomButtonConstraints.insets = new Insets(2, 2, 4, 6 + 16);
+        }
+
         GridBagLayout layout = new GridBagLayout();
 
         configurationChooser.addChoosableFileFilter(
             new ExtensionFileFilter(msg("proExtension"), new String[] { ".pro" }));
 
         // Create the opening panel.
-        //JLabel titleLabel = new JLabel("ProGuard", JLabel.CENTER);
-        //titleLabel.setFont(new Font("serif", Font.BOLD, 40));
-        //titleLabel.setForeground(Color.gray);
-
         Font font = new Font("sansserif", Font.BOLD, 50);
         Color fontColor = Color.white;
 
@@ -386,8 +389,8 @@ public class ProGuardGUI extends JFrame
         optimizationPanel.add(additionalNoSideEffectsPanel, stretchPanelConstraints);
 
         // Create the options panel.
-        JButton printSeedsBrowseButton   = createBrowseButton(printSeedsTextField,
-                                                              msg("selectSeedsFile"));
+        JButton printSeedsBrowseButton = createBrowseButton(printSeedsTextField,
+                                                            msg("selectSeedsFile"));
 
         JPanel consistencyPanel = new JPanel(layout);
         addBorder(consistencyPanel, "consistencyAndCorrectness");
@@ -416,6 +419,9 @@ public class ProGuardGUI extends JFrame
 
         optionsPanel.add(consistencyPanel,  panelConstraints);
 
+        addBorder(whyAreYouKeepingPanel, "whyAreYouKeeping");
+        optionsPanel.add(whyAreYouKeepingPanel, stretchPanelConstraints);
+
         // Create the process panel.
         consoleTextArea.setOpaque(false);
         consoleTextArea.setEditable(false);
@@ -563,19 +569,27 @@ public class ProGuardGUI extends JFrame
             ConfigurationParser parser = new ConfigurationParser(
                 this.getClass().getResource(BOILERPLATE_CONFIGURATION));
             Configuration configuration = new Configuration();
-            parser.parse(configuration);
 
-            // We're interested in the keep options.
-            boilerplateKeep = new ClassSpecification[configuration.keep.size()];
-            configuration.keep.toArray(boilerplateKeep);
+            try
+            {
+                parser.parse(configuration);
+
+                // We're interested in the keep options.
+                boilerplateKeep = new ClassSpecification[configuration.keep.size()];
+                configuration.keep.toArray(boilerplateKeep);
 
-            // We're interested in the keep names options.
-            boilerplateKeepNames = new ClassSpecification[configuration.keepNames.size()];
-            configuration.keepNames.toArray(boilerplateKeepNames);
+                // We're interested in the keep names options.
+                boilerplateKeepNames = new ClassSpecification[configuration.keepNames.size()];
+                configuration.keepNames.toArray(boilerplateKeepNames);
 
-            // We're interested in the side effects options.
-            boilerplateNoSideEffectMethods = new ClassSpecification[configuration.assumeNoSideEffects.size()];
-            configuration.assumeNoSideEffects.toArray(boilerplateNoSideEffectMethods);
+                // We're interested in the side effects options.
+                boilerplateNoSideEffectMethods = new ClassSpecification[configuration.assumeNoSideEffects.size()];
+                configuration.assumeNoSideEffects.toArray(boilerplateNoSideEffectMethods);
+            }
+            finally
+            {
+                parser.close();
+            }
         }
         catch (Exception ex)
         {
@@ -815,6 +829,9 @@ public class ProGuardGUI extends JFrame
         // options have been removed from the list.
         additionalNoSideEffectsPanel.setClassSpecifications(configuration.assumeNoSideEffects);
 
+        // Set up the "why are you keeping" options.
+        whyAreYouKeepingPanel.setClassSpecifications(configuration.whyAreYouKeeping);
+
         // Set up the other options.
         shrinkCheckBox                          .setSelected(configuration.shrink);
         printUsageCheckBox                      .setSelected(configuration.printUsage != null);
@@ -825,9 +842,9 @@ public class ProGuardGUI extends JFrame
         obfuscateCheckBox                       .setSelected(configuration.obfuscate);
         printMappingCheckBox                    .setSelected(configuration.printMapping != null);
         applyMappingCheckBox                    .setSelected(configuration.applyMapping != null);
-        obfuscationDictionaryCheckBox           .setSelected(configuration.defaultPackage != null);
+        obfuscationDictionaryCheckBox           .setSelected(configuration.obfuscationDictionary != null);
         overloadAggressivelyCheckBox            .setSelected(configuration.overloadAggressively);
-        defaultPackageCheckBox                  .setSelected(configuration.obfuscationDictionary != null);
+        defaultPackageCheckBox                  .setSelected(configuration.defaultPackage != null);
         useMixedCaseClassNamesCheckBox          .setSelected(configuration.useMixedCaseClassNames);
         keepAttributesCheckBox                  .setSelected(configuration.keepAttributes != null);
         newSourceFileAttributeCheckBox          .setSelected(configuration.newSourceFileAttribute != null);
@@ -840,18 +857,18 @@ public class ProGuardGUI extends JFrame
         skipNonPublicLibraryClassesCheckBox     .setSelected(configuration.skipNonPublicLibraryClasses);
         skipNonPublicLibraryClassMembersCheckBox.setSelected(configuration.skipNonPublicLibraryClassMembers);
 
-        printUsageTextField                     .setText(configuration.printUsage);
-        printMappingTextField                   .setText(configuration.printMapping);
-        applyMappingTextField                   .setText(configuration.applyMapping);
-        obfuscationDictionaryTextField          .setText(configuration.obfuscationDictionary);
+        printUsageTextField                     .setText(fileName(configuration.printUsage));
+        printMappingTextField                   .setText(fileName(configuration.printMapping));
+        applyMappingTextField                   .setText(fileName(configuration.applyMapping));
+        obfuscationDictionaryTextField          .setText(fileName(configuration.obfuscationDictionary));
         defaultPackageTextField                 .setText(configuration.defaultPackage);
         keepAttributesTextField                 .setText(configuration.keepAttributes         == null ? KEEP_ATTRIBUTE_DEFAULT : ListUtil.commaSeparatedString(configuration.keepAttributes));
         newSourceFileAttributeTextField         .setText(configuration.newSourceFileAttribute == null ? SOURCE_FILE_ATTRIBUTE_DEFAULT : configuration.newSourceFileAttribute);
-        printSeedsTextField                     .setText(configuration.printSeeds);
+        printSeedsTextField                     .setText(fileName(configuration.printSeeds));
 
         if (configuration.printMapping != null)
         {
-            reTraceMappingTextField.setText(configuration.printMapping);
+            reTraceMappingTextField.setText(fileName(configuration.printMapping));
         }
     }
 
@@ -946,24 +963,28 @@ public class ProGuardGUI extends JFrame
         }
 
 
+        // Collect the "why are you keeping" options.
+        configuration.whyAreYouKeeping = whyAreYouKeepingPanel.getClassSpecifications();
+
+
         // Get the other options.
         configuration.shrink                           = shrinkCheckBox                          .isSelected();
-        configuration.printUsage                       = printUsageCheckBox                      .isSelected() ? printUsageTextField                                .getText() : null;
+        configuration.printUsage                       = printUsageCheckBox                      .isSelected() ? new File(printUsageTextField                       .getText()) : null;
 
         configuration.optimize                         = optimizeCheckBox                        .isSelected();
         configuration.allowAccessModification          = allowAccessModificationCheckBox         .isSelected();
 
         configuration.obfuscate                        = obfuscateCheckBox                       .isSelected();
-        configuration.printMapping                     = printMappingCheckBox                    .isSelected() ? printMappingTextField                              .getText() : null;
-        configuration.applyMapping                     = applyMappingCheckBox                    .isSelected() ? applyMappingTextField                              .getText() : null;
-        configuration.obfuscationDictionary            = obfuscationDictionaryCheckBox           .isSelected() ? obfuscationDictionaryTextField                     .getText()  : null;
+        configuration.printMapping                     = printMappingCheckBox                    .isSelected() ? new File(printMappingTextField                     .getText()) : null;
+        configuration.applyMapping                     = applyMappingCheckBox                    .isSelected() ? new File(applyMappingTextField                     .getText()) : null;
+        configuration.obfuscationDictionary            = obfuscationDictionaryCheckBox           .isSelected() ? new File(obfuscationDictionaryTextField            .getText()) : null;
         configuration.overloadAggressively             = overloadAggressivelyCheckBox            .isSelected();
-        configuration.defaultPackage                   = defaultPackageCheckBox                  .isSelected() ? defaultPackageTextField                            .getText()  : null;
+        configuration.defaultPackage                   = defaultPackageCheckBox                  .isSelected() ?          defaultPackageTextField                   .getText()  : null;
         configuration.useMixedCaseClassNames           = useMixedCaseClassNamesCheckBox          .isSelected();
         configuration.keepAttributes                   = keepAttributesCheckBox                  .isSelected() ? ListUtil.commaSeparatedList(keepAttributesTextField.getText()) : null;
-        configuration.newSourceFileAttribute           = newSourceFileAttributeCheckBox          .isSelected() ? newSourceFileAttributeTextField                    .getText()  : null;
+        configuration.newSourceFileAttribute           = newSourceFileAttributeCheckBox          .isSelected() ?          newSourceFileAttributeTextField           .getText()  : null;
 
-        configuration.printSeeds                       = printSeedsCheckBox                      .isSelected() ? printSeedsTextField                                .getText() : null;
+        configuration.printSeeds                       = printSeedsCheckBox                      .isSelected() ? new File(printSeedsTextField                       .getText()) : null;
         configuration.verbose                          = verboseCheckBox                         .isSelected();
         configuration.note                             = noteCheckBox                            .isSelected();
         configuration.warn                             = warnCheckBox                            .isSelected();
@@ -1081,29 +1102,41 @@ public class ProGuardGUI extends JFrame
     /**
      * Loads the given ProGuard configuration into the GUI.
      */
-    private void loadConfiguration(String fileName)
+    private void loadConfiguration(File file)
     {
+        // Set the default directory and file in the file choosers.
+        configurationChooser.setSelectedFile(file.getAbsoluteFile());
+        fileChooser.setCurrentDirectory(file.getAbsoluteFile().getParentFile());
+
         try
         {
             // Parse the configuration file.
-            ConfigurationParser parser = new ConfigurationParser(fileName);
+            ConfigurationParser parser = new ConfigurationParser(file);
             Configuration configuration = new Configuration();
-            parser.parse(configuration);
 
-            // Let the GUI reflect the configuration.
-            setProGuardConfiguration(configuration);
+            try
+            {
+                parser.parse(configuration);
+
+                // Let the GUI reflect the configuration.
+                setProGuardConfiguration(configuration);
+            }
+            catch (ParseException ex)
+            {
+                JOptionPane.showMessageDialog(getContentPane(),
+                                              msg("cantParseConfigurationFile", file.getPath()),
+                                              msg("warning"),
+                                              JOptionPane.ERROR_MESSAGE);
+            }
+            finally
+            {
+                parser.close();
+            }
         }
         catch (IOException ex)
         {
             JOptionPane.showMessageDialog(getContentPane(),
-                                          msg("cantOpenConfigurationFile", fileName),
-                                          msg("warning"),
-                                          JOptionPane.ERROR_MESSAGE);
-        }
-        catch (ParseException ex)
-        {
-            JOptionPane.showMessageDialog(getContentPane(),
-                                          msg("cantParseConfigurationFile", fileName),
+                                          msg("cantOpenConfigurationFile", file.getPath()),
                                           msg("warning"),
                                           JOptionPane.ERROR_MESSAGE);
         }
@@ -1120,10 +1153,25 @@ public class ProGuardGUI extends JFrame
             // Parse the configuration file.
             ConfigurationParser parser = new ConfigurationParser(url);
             Configuration configuration = new Configuration();
-            parser.parse(configuration);
 
-            // Let the GUI reflect the configuration.
-            setProGuardConfiguration(configuration);
+            try
+            {
+                parser.parse(configuration);
+
+                // Let the GUI reflect the configuration.
+                setProGuardConfiguration(configuration);
+            }
+            catch (ParseException ex)
+            {
+                JOptionPane.showMessageDialog(getContentPane(),
+                                              msg("cantParseConfigurationFile", url),
+                                              msg("warning"),
+                                              JOptionPane.ERROR_MESSAGE);
+            }
+            finally
+            {
+                parser.close();
+            }
         }
         catch (IOException ex)
         {
@@ -1132,32 +1180,25 @@ public class ProGuardGUI extends JFrame
                                           msg("warning"),
                                           JOptionPane.ERROR_MESSAGE);
         }
-        catch (ParseException ex)
-        {
-            JOptionPane.showMessageDialog(getContentPane(),
-                                          msg("cantParseConfigurationFile", url),
-                                          msg("warning"),
-                                          JOptionPane.ERROR_MESSAGE);
-        }
     }
 
 
     /**
      * Saves the current ProGuard configuration to the given file.
      */
-    private void saveConfiguration(String fileName)
+    private void saveConfiguration(File file)
     {
         try
         {
             // Save the configuration file.
-            ConfigurationWriter writer = new ConfigurationWriter(fileName);
+            ConfigurationWriter writer = new ConfigurationWriter(file);
             writer.write(getProGuardConfiguration());
             writer.close();
         }
         catch (Exception ex)
         {
             JOptionPane.showMessageDialog(getContentPane(),
-                                          msg("cantSaveConfigurationFile", fileName),
+                                          msg("cantSaveConfigurationFile", file.getPath()),
                                           msg("warning"),
                                           JOptionPane.ERROR_MESSAGE);
         }
@@ -1204,10 +1245,7 @@ public class ProGuardGUI extends JFrame
             int returnValue = configurationChooser.showOpenDialog(ProGuardGUI.this);
             if (returnValue == JFileChooser.APPROVE_OPTION)
             {
-                File selectedFile = configurationChooser.getSelectedFile();
-                String fileName = selectedFile.getPath();
-
-                loadConfiguration(fileName);
+                loadConfiguration(configurationChooser.getSelectedFile());
             }
         }
     }
@@ -1226,10 +1264,7 @@ public class ProGuardGUI extends JFrame
             int returnVal = configurationChooser.showSaveDialog(ProGuardGUI.this);
             if (returnVal == JFileChooser.APPROVE_OPTION)
             {
-                File selectedFile = configurationChooser.getSelectedFile();
-                String fileName = selectedFile.getPath();
-
-                saveConfiguration(fileName);
+                saveConfiguration(configurationChooser.getSelectedFile());
             }
         }
     }
@@ -1339,7 +1374,7 @@ public class ProGuardGUI extends JFrame
                 systemOutRedirected = true;
 
                 boolean verbose            = reTraceVerboseCheckBox.isSelected();
-                String  retraceMappingFile = reTraceMappingTextField.getText();
+                File    retraceMappingFile = new File(reTraceMappingTextField.getText());
                 String  stackTrace         = stackTraceTextArea.getText();
 
                 // Create the ReTrace runnable.
@@ -1358,6 +1393,14 @@ public class ProGuardGUI extends JFrame
     // Small utility methods.
 
     /**
+     * Returns the file name of the given file, if any.
+     */
+    private String fileName(File file)
+    {
+        return file == null ? "" : file.getAbsolutePath();
+    }
+
+    /**
      * Returns the message from the GUI resources that corresponds to the given
      * key.
      */
@@ -1408,7 +1451,7 @@ public class ProGuardGUI extends JFrame
         // Load an initial configuration, if specified.
         if (argIndex < args.length)
         {
-            gui.loadConfiguration(args[argIndex]);
+            gui.loadConfiguration(new File(args[argIndex]));
             argIndex++;
         }
 
diff --git a/src/proguard/gui/ProGuardRunnable.java b/src/proguard/gui/ProGuardRunnable.java
index ad5f31b..c75a636 100644
--- a/src/proguard/gui/ProGuardRunnable.java
+++ b/src/proguard/gui/ProGuardRunnable.java
@@ -1,8 +1,8 @@
-/* $Id: ProGuardRunnable.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+/* $Id: ProGuardRunnable.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -83,9 +83,14 @@ class ProGuardRunnable implements Runnable
 
             // Run it.
             proGuard.execute();
+
+            // Print out the completion message.
+            System.out.println("Processing completed successfully");
         }
         catch (Exception ex)
         {
+            //ex.printStackTrace();
+
             // Print out the exception message.
             System.out.println(ex.getMessage());
 
diff --git a/src/proguard/gui/ReTraceRunnable.java b/src/proguard/gui/ReTraceRunnable.java
index 29cca05..960699b 100644
--- a/src/proguard/gui/ReTraceRunnable.java
+++ b/src/proguard/gui/ReTraceRunnable.java
@@ -1,8 +1,8 @@
-/* $Id: ReTraceRunnable.java,v 1.6 2004/08/21 21:36:03 eric Exp $
+/* $Id: ReTraceRunnable.java,v 1.8 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -39,7 +39,7 @@ class ReTraceRunnable implements Runnable
 {
     private JTextArea consoleTextArea;
     private boolean   verbose;
-    private String    retraceMappingFile;
+    private File      mappingFile;
     private String    stackTrace;
 
 
@@ -48,17 +48,17 @@ class ReTraceRunnable implements Runnable
      * @param consoleTextArea the text area to send the console output to.
      * @param verbose         specifies whether the de-obfuscated stack trace
      *                        should be verbose.
-     * @param mappingFileName the mapping file that was written out by ProGuard.
+     * @param mappingFile     the mapping file that was written out by ProGuard.
      */
     public ReTraceRunnable(JTextArea consoleTextArea,
                            boolean   verbose,
-                           String    retraceMappingFile,
+                           File      mappingFile,
                            String    stackTrace)
     {
-        this.consoleTextArea    = consoleTextArea;
-        this.verbose            = verbose;
-        this.retraceMappingFile = retraceMappingFile;
-        this.stackTrace         = stackTrace;
+        this.consoleTextArea  = consoleTextArea;
+        this.verbose          = verbose;
+        this.mappingFile      = mappingFile;
+        this.stackTrace       = stackTrace;
     }
 
 
@@ -89,7 +89,7 @@ class ReTraceRunnable implements Runnable
         {
             // Create a new ProGuard object with the GUI's configuration.
             ReTrace reTrace = new ReTrace(verbose,
-                                          retraceMappingFile);
+                                          mappingFile);
 
             // Run it.
             reTrace.execute();
diff --git a/src/proguard/gui/SwingUtil.java b/src/proguard/gui/SwingUtil.java
index 22f3da4..ddfca3a 100644
--- a/src/proguard/gui/SwingUtil.java
+++ b/src/proguard/gui/SwingUtil.java
@@ -1,8 +1,8 @@
-/* $Id: SwingUtil.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+/* $Id: SwingUtil.java,v 1.5 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/TabbedPane.java b/src/proguard/gui/TabbedPane.java
index e61c8ba..e06aa80 100644
--- a/src/proguard/gui/TabbedPane.java
+++ b/src/proguard/gui/TabbedPane.java
@@ -1,8 +1,8 @@
-/* $Id: TabbedPane.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: TabbedPane.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/TextAreaOutputStream.java b/src/proguard/gui/TextAreaOutputStream.java
index e06df07..2d42e4d 100644
--- a/src/proguard/gui/TextAreaOutputStream.java
+++ b/src/proguard/gui/TextAreaOutputStream.java
@@ -1,8 +1,8 @@
-/* $Id: TextAreaOutputStream.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+/* $Id: TextAreaOutputStream.java,v 1.6 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/BufferedSprite.java b/src/proguard/gui/splash/BufferedSprite.java
index 684f977..2972056 100644
--- a/src/proguard/gui/splash/BufferedSprite.java
+++ b/src/proguard/gui/splash/BufferedSprite.java
@@ -1,8 +1,8 @@
-/* $Id: BufferedSprite.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: BufferedSprite.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/CircleSprite.java b/src/proguard/gui/splash/CircleSprite.java
index 21484df..e3aa48f 100644
--- a/src/proguard/gui/splash/CircleSprite.java
+++ b/src/proguard/gui/splash/CircleSprite.java
@@ -1,8 +1,8 @@
-/* $Id: CircleSprite.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: CircleSprite.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/ClipSprite.java b/src/proguard/gui/splash/ClipSprite.java
index 0cad063..6a6e9a5 100644
--- a/src/proguard/gui/splash/ClipSprite.java
+++ b/src/proguard/gui/splash/ClipSprite.java
@@ -1,8 +1,8 @@
-/* $Id: ClipSprite.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: ClipSprite.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/CompositeSprite.java b/src/proguard/gui/splash/CompositeSprite.java
index 8a27b35..1c9475d 100644
--- a/src/proguard/gui/splash/CompositeSprite.java
+++ b/src/proguard/gui/splash/CompositeSprite.java
@@ -1,8 +1,8 @@
-/* $Id: CompositeSprite.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: CompositeSprite.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/ImageSprite.java b/src/proguard/gui/splash/ImageSprite.java
index cf62703..feecbe7 100644
--- a/src/proguard/gui/splash/ImageSprite.java
+++ b/src/proguard/gui/splash/ImageSprite.java
@@ -1,8 +1,8 @@
-/* $Id: ImageSprite.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: ImageSprite.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/LinearColor.java b/src/proguard/gui/splash/LinearColor.java
index 60c3666..f450d69 100644
--- a/src/proguard/gui/splash/LinearColor.java
+++ b/src/proguard/gui/splash/LinearColor.java
@@ -1,8 +1,8 @@
-/* $Id: LinearColor.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: LinearColor.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/LinearDouble.java b/src/proguard/gui/splash/LinearDouble.java
index 113a759..c48b99f 100644
--- a/src/proguard/gui/splash/LinearDouble.java
+++ b/src/proguard/gui/splash/LinearDouble.java
@@ -1,8 +1,8 @@
-/* $Id: LinearDouble.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: LinearDouble.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/LinearInt.java b/src/proguard/gui/splash/LinearInt.java
index 909fc90..ca7cca4 100644
--- a/src/proguard/gui/splash/LinearInt.java
+++ b/src/proguard/gui/splash/LinearInt.java
@@ -1,8 +1,8 @@
-/* $Id: LinearInt.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: LinearInt.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/LinearTiming.java b/src/proguard/gui/splash/LinearTiming.java
index 1dc3810..d2d8197 100644
--- a/src/proguard/gui/splash/LinearTiming.java
+++ b/src/proguard/gui/splash/LinearTiming.java
@@ -1,8 +1,8 @@
-/* $Id: LinearTiming.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: LinearTiming.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/OverrideGraphics2D.java b/src/proguard/gui/splash/OverrideGraphics2D.java
index 4947bcd..c3955f4 100644
--- a/src/proguard/gui/splash/OverrideGraphics2D.java
+++ b/src/proguard/gui/splash/OverrideGraphics2D.java
@@ -1,8 +1,8 @@
-/* $Id: OverrideGraphics2D.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: OverrideGraphics2D.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/RectangleSprite.java b/src/proguard/gui/splash/RectangleSprite.java
index 146c08d..7f2006f 100644
--- a/src/proguard/gui/splash/RectangleSprite.java
+++ b/src/proguard/gui/splash/RectangleSprite.java
@@ -1,8 +1,8 @@
-/* $Id: RectangleSprite.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: RectangleSprite.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/SawToothTiming.java b/src/proguard/gui/splash/SawToothTiming.java
index 0c7c1ab..96ff02e 100644
--- a/src/proguard/gui/splash/SawToothTiming.java
+++ b/src/proguard/gui/splash/SawToothTiming.java
@@ -1,8 +1,8 @@
-/* $Id: SawToothTiming.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: SawToothTiming.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/ShadowedSprite.java b/src/proguard/gui/splash/ShadowedSprite.java
index 64639e6..365482f 100644
--- a/src/proguard/gui/splash/ShadowedSprite.java
+++ b/src/proguard/gui/splash/ShadowedSprite.java
@@ -1,8 +1,8 @@
-/* $Id: ShadowedSprite.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: ShadowedSprite.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/SineTiming.java b/src/proguard/gui/splash/SineTiming.java
index 151ec73..1dabdab 100644
--- a/src/proguard/gui/splash/SineTiming.java
+++ b/src/proguard/gui/splash/SineTiming.java
@@ -1,8 +1,8 @@
-/* $Id: SineTiming.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: SineTiming.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/SmoothTiming.java b/src/proguard/gui/splash/SmoothTiming.java
index 89a3cd7..b31af7a 100644
--- a/src/proguard/gui/splash/SmoothTiming.java
+++ b/src/proguard/gui/splash/SmoothTiming.java
@@ -1,8 +1,8 @@
-/* $Id: SmoothTiming.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: SmoothTiming.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/SplashPanel.java b/src/proguard/gui/splash/SplashPanel.java
index 6d30f8a..505376e 100644
--- a/src/proguard/gui/splash/SplashPanel.java
+++ b/src/proguard/gui/splash/SplashPanel.java
@@ -1,8 +1,8 @@
-/* $Id: SplashPanel.java,v 1.10 2004/08/15 12:39:30 eric Exp $
+/* $Id: SplashPanel.java,v 1.11 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/Sprite.java b/src/proguard/gui/splash/Sprite.java
index 01e7fb2..18c66cc 100644
--- a/src/proguard/gui/splash/Sprite.java
+++ b/src/proguard/gui/splash/Sprite.java
@@ -1,8 +1,8 @@
-/* $Id: Sprite.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+/* $Id: Sprite.java,v 1.6 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/TextSprite.java b/src/proguard/gui/splash/TextSprite.java
index a31c9f6..0090440 100644
--- a/src/proguard/gui/splash/TextSprite.java
+++ b/src/proguard/gui/splash/TextSprite.java
@@ -1,8 +1,8 @@
-/* $Id: TextSprite.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: TextSprite.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/TimeSwitchSprite.java b/src/proguard/gui/splash/TimeSwitchSprite.java
index 53bd207..c84921f 100644
--- a/src/proguard/gui/splash/TimeSwitchSprite.java
+++ b/src/proguard/gui/splash/TimeSwitchSprite.java
@@ -1,8 +1,8 @@
-/* $Id: TimeSwitchSprite.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: TimeSwitchSprite.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/Timing.java b/src/proguard/gui/splash/Timing.java
index e9b0029..5fcc165 100644
--- a/src/proguard/gui/splash/Timing.java
+++ b/src/proguard/gui/splash/Timing.java
@@ -1,8 +1,8 @@
-/* $Id: Timing.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+/* $Id: Timing.java,v 1.6 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/TypeWriterString.java b/src/proguard/gui/splash/TypeWriterString.java
index 6c1fd27..b8b2ff9 100644
--- a/src/proguard/gui/splash/TypeWriterString.java
+++ b/src/proguard/gui/splash/TypeWriterString.java
@@ -1,8 +1,8 @@
-/* $Id: TypeWriterString.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: TypeWriterString.java,v 1.7 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/VariableColor.java b/src/proguard/gui/splash/VariableColor.java
index 715d353..c8b5b43 100644
--- a/src/proguard/gui/splash/VariableColor.java
+++ b/src/proguard/gui/splash/VariableColor.java
@@ -1,8 +1,8 @@
-/* $Id: VariableColor.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+/* $Id: VariableColor.java,v 1.6 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/VariableDouble.java b/src/proguard/gui/splash/VariableDouble.java
index 78dab89..a795a2d 100644
--- a/src/proguard/gui/splash/VariableDouble.java
+++ b/src/proguard/gui/splash/VariableDouble.java
@@ -1,8 +1,8 @@
-/* $Id: VariableDouble.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+/* $Id: VariableDouble.java,v 1.6 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/VariableFont.java b/src/proguard/gui/splash/VariableFont.java
index 9da8e73..f6aef05 100644
--- a/src/proguard/gui/splash/VariableFont.java
+++ b/src/proguard/gui/splash/VariableFont.java
@@ -1,8 +1,8 @@
-/* $Id: VariableFont.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+/* $Id: VariableFont.java,v 1.6 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/VariableInt.java b/src/proguard/gui/splash/VariableInt.java
index 53f583d..59d6711 100644
--- a/src/proguard/gui/splash/VariableInt.java
+++ b/src/proguard/gui/splash/VariableInt.java
@@ -1,8 +1,8 @@
-/* $Id: VariableInt.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+/* $Id: VariableInt.java,v 1.6 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/VariableSizeFont.java b/src/proguard/gui/splash/VariableSizeFont.java
index db0d9d5..0455003 100644
--- a/src/proguard/gui/splash/VariableSizeFont.java
+++ b/src/proguard/gui/splash/VariableSizeFont.java
@@ -1,8 +1,8 @@
-/* $Id: VariableSizeFont.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+/* $Id: VariableSizeFont.java,v 1.6 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/gui/splash/VariableString.java b/src/proguard/gui/splash/VariableString.java
index 63e9e03..6198160 100644
--- a/src/proguard/gui/splash/VariableString.java
+++ b/src/proguard/gui/splash/VariableString.java
@@ -1,8 +1,8 @@
-/* $Id: VariableString.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+/* $Id: VariableString.java,v 1.6 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/CascadingDataEntryWriter.java b/src/proguard/io/CascadingDataEntryWriter.java
index f967ec4..f1d8ffe 100644
--- a/src/proguard/io/CascadingDataEntryWriter.java
+++ b/src/proguard/io/CascadingDataEntryWriter.java
@@ -1,8 +1,8 @@
-/* $Id: CascadingDataEntryWriter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: CascadingDataEntryWriter.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/ClassFileFilter.java b/src/proguard/io/ClassFileFilter.java
index b439b52..cd81dbf 100644
--- a/src/proguard/io/ClassFileFilter.java
+++ b/src/proguard/io/ClassFileFilter.java
@@ -1,8 +1,8 @@
-/* $Id: ClassFileFilter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: ClassFileFilter.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/ClassFileReader.java b/src/proguard/io/ClassFileReader.java
index 75b33ea..a6e8ab5 100644
--- a/src/proguard/io/ClassFileReader.java
+++ b/src/proguard/io/ClassFileReader.java
@@ -1,8 +1,8 @@
-/* $Id: ClassFileReader.java,v 1.3 2004/11/20 15:08:57 eric Exp $
+/* $Id: ClassFileReader.java,v 1.6 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -21,6 +21,7 @@
 package proguard.io;
 
 import proguard.classfile.*;
+import proguard.classfile.util.ClassUtil;
 import proguard.classfile.visitor.*;
 
 import java.io.*;
@@ -42,6 +43,7 @@ public class ClassFileReader implements DataEntryReader
     private boolean          isLibrary;
     private boolean          skipNonPublicLibraryClasses;
     private boolean          skipNonPublicLibraryClassMembers;
+    private boolean          note;
     private ClassFileVisitor classFileVisitor;
 
 
@@ -52,11 +54,13 @@ public class ClassFileReader implements DataEntryReader
     public ClassFileReader(boolean          isLibrary,
                            boolean          skipNonPublicLibraryClasses,
                            boolean          skipNonPublicLibraryClassMembers,
+                           boolean          note,
                            ClassFileVisitor classFileVisitor)
     {
         this.isLibrary                        = isLibrary;
         this.skipNonPublicLibraryClasses      = skipNonPublicLibraryClasses;
         this.skipNonPublicLibraryClassMembers = skipNonPublicLibraryClassMembers;
+        this.note                             = note;
         this.classFileVisitor                 = classFileVisitor;
     }
 
@@ -81,6 +85,12 @@ public class ClassFileReader implements DataEntryReader
             // Apply the visitor.
             if (classFile != null)
             {
+                if (note &&
+                    !dataEntry.getName().equals(classFile.getName()+ClassConstants.CLASS_FILE_EXTENSION))
+                {
+                    System.err.println("Note: class file [" + dataEntry.getName() + "] unexpectedly contains class [" + ClassUtil.externalClassName(classFile.getName()) + "]");
+                }
+
                 classFile.accept(classFileVisitor);
             }
 
diff --git a/src/proguard/io/ClassFileRewriter.java b/src/proguard/io/ClassFileRewriter.java
index e50f506..4d95b35 100644
--- a/src/proguard/io/ClassFileRewriter.java
+++ b/src/proguard/io/ClassFileRewriter.java
@@ -1,8 +1,8 @@
-/* $Id: ClassFileRewriter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: ClassFileRewriter.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/DataEntry.java b/src/proguard/io/DataEntry.java
index 03aeb9d..28fb994 100644
--- a/src/proguard/io/DataEntry.java
+++ b/src/proguard/io/DataEntry.java
@@ -1,8 +1,8 @@
-/* $Id: DataEntry.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: DataEntry.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/DataEntryCopier.java b/src/proguard/io/DataEntryCopier.java
index 23f0e5b..125be44 100644
--- a/src/proguard/io/DataEntryCopier.java
+++ b/src/proguard/io/DataEntryCopier.java
@@ -1,8 +1,8 @@
-/* $Id: DataEntryCopier.java,v 1.3 2004/08/15 12:39:30 eric Exp $
+/* $Id: DataEntryCopier.java,v 1.4 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/DataEntryPump.java b/src/proguard/io/DataEntryPump.java
index 2b68072..afb813c 100644
--- a/src/proguard/io/DataEntryPump.java
+++ b/src/proguard/io/DataEntryPump.java
@@ -1,8 +1,8 @@
-/* $Id: DataEntryPump.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: DataEntryPump.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/DataEntryReader.java b/src/proguard/io/DataEntryReader.java
index 7a1a7d3..7c456a9 100644
--- a/src/proguard/io/DataEntryReader.java
+++ b/src/proguard/io/DataEntryReader.java
@@ -1,8 +1,8 @@
-/* $Id: DataEntryReader.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: DataEntryReader.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/DataEntryWriter.java b/src/proguard/io/DataEntryWriter.java
index 1677cc3..ee5ecaf 100644
--- a/src/proguard/io/DataEntryWriter.java
+++ b/src/proguard/io/DataEntryWriter.java
@@ -1,8 +1,8 @@
-/* $Id: DataEntryWriter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: DataEntryWriter.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/DirectoryPump.java b/src/proguard/io/DirectoryPump.java
index 1598338..f57eb1a 100644
--- a/src/proguard/io/DirectoryPump.java
+++ b/src/proguard/io/DirectoryPump.java
@@ -1,8 +1,8 @@
-/* $Id: DirectoryPump.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: DirectoryPump.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/DirectoryWriter.java b/src/proguard/io/DirectoryWriter.java
index 536e4ed..1df75a6 100644
--- a/src/proguard/io/DirectoryWriter.java
+++ b/src/proguard/io/DirectoryWriter.java
@@ -1,8 +1,8 @@
-/* $Id: DirectoryWriter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: DirectoryWriter.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/FileDataEntry.java b/src/proguard/io/FileDataEntry.java
index d5b794e..8250e91 100644
--- a/src/proguard/io/FileDataEntry.java
+++ b/src/proguard/io/FileDataEntry.java
@@ -1,8 +1,8 @@
-/* $Id: FileDataEntry.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: FileDataEntry.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/FilteredDataEntryReader.java b/src/proguard/io/FilteredDataEntryReader.java
index 81cf923..6e82a04 100644
--- a/src/proguard/io/FilteredDataEntryReader.java
+++ b/src/proguard/io/FilteredDataEntryReader.java
@@ -1,8 +1,8 @@
-/* $Id: FilteredDataEntryReader.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: FilteredDataEntryReader.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/FilteredDataEntryWriter.java b/src/proguard/io/FilteredDataEntryWriter.java
index ffd0dc3..e6bfb0c 100644
--- a/src/proguard/io/FilteredDataEntryWriter.java
+++ b/src/proguard/io/FilteredDataEntryWriter.java
@@ -1,8 +1,8 @@
-/* $Id: FilteredDataEntryWriter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: FilteredDataEntryWriter.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/Finisher.java b/src/proguard/io/Finisher.java
index 18b2413..9538136 100644
--- a/src/proguard/io/Finisher.java
+++ b/src/proguard/io/Finisher.java
@@ -1,8 +1,8 @@
-/* $Id: Finisher.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: Finisher.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/JarReader.java b/src/proguard/io/JarReader.java
index 3210122..388a565 100644
--- a/src/proguard/io/JarReader.java
+++ b/src/proguard/io/JarReader.java
@@ -1,8 +1,8 @@
-/* $Id: JarReader.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: JarReader.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/JarWriter.java b/src/proguard/io/JarWriter.java
index 9e62949..7f79e51 100644
--- a/src/proguard/io/JarWriter.java
+++ b/src/proguard/io/JarWriter.java
@@ -1,8 +1,8 @@
-/* $Id: JarWriter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: JarWriter.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/ParentDataEntryWriter.java b/src/proguard/io/ParentDataEntryWriter.java
index 097965b..874f367 100644
--- a/src/proguard/io/ParentDataEntryWriter.java
+++ b/src/proguard/io/ParentDataEntryWriter.java
@@ -1,8 +1,8 @@
-/* $Id: ParentDataEntryWriter.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: ParentDataEntryWriter.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/RenamedDataEntry.java b/src/proguard/io/RenamedDataEntry.java
index 79be047..cfc6864 100644
--- a/src/proguard/io/RenamedDataEntry.java
+++ b/src/proguard/io/RenamedDataEntry.java
@@ -1,8 +1,8 @@
-/* $Id: RenamedDataEntry.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: RenamedDataEntry.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/io/ZipDataEntry.java b/src/proguard/io/ZipDataEntry.java
index ff7a3bc..352d135 100644
--- a/src/proguard/io/ZipDataEntry.java
+++ b/src/proguard/io/ZipDataEntry.java
@@ -1,8 +1,8 @@
-/* $Id: ZipDataEntry.java,v 1.3 2004/08/15 12:39:30 eric Exp $
+/* $Id: ZipDataEntry.java,v 1.4 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/obfuscate/AttributeShrinker.java b/src/proguard/obfuscate/AttributeShrinker.java
index 1fb95ef..5e80339 100644
--- a/src/proguard/obfuscate/AttributeShrinker.java
+++ b/src/proguard/obfuscate/AttributeShrinker.java
@@ -1,8 +1,8 @@
-/* $Id: AttributeShrinker.java,v 1.16 2004/10/10 20:56:58 eric Exp $
+/* $Id: AttributeShrinker.java,v 1.17 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/obfuscate/AttributeUsageMarker.java b/src/proguard/obfuscate/AttributeUsageMarker.java
index 4f8ecb0..102c1a2 100644
--- a/src/proguard/obfuscate/AttributeUsageMarker.java
+++ b/src/proguard/obfuscate/AttributeUsageMarker.java
@@ -1,8 +1,8 @@
-/* $Id: AttributeUsageMarker.java,v 1.23 2004/11/20 15:41:24 eric Exp $
+/* $Id: AttributeUsageMarker.java,v 1.24 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/obfuscate/ClassFileObfuscator.java b/src/proguard/obfuscate/ClassFileObfuscator.java
index 98f0275..dd65f96 100644
--- a/src/proguard/obfuscate/ClassFileObfuscator.java
+++ b/src/proguard/obfuscate/ClassFileObfuscator.java
@@ -1,8 +1,8 @@
-/* $Id: ClassFileObfuscator.java,v 1.23 2004/11/01 21:17:51 eric Exp $
+/* $Id: ClassFileObfuscator.java,v 1.24 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/obfuscate/ClassFileOpener.java b/src/proguard/obfuscate/ClassFileOpener.java
new file mode 100644
index 0000000..133ec94
--- /dev/null
+++ b/src/proguard/obfuscate/ClassFileOpener.java
@@ -0,0 +1,117 @@
+/* $Id: ClassFileOpener.java,v 1.2 2005/06/11 13:13:15 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import proguard.classfile.*;
+import proguard.classfile.editor.ConstantPoolEditor;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This <code>ClassFileVisitor</code> makes package visible classes and class
+ * members public.
+ *
+ * @author Eric Lafortune
+ */
+public class ClassFileOpener
+  implements ClassFileVisitor,
+             MemberInfoVisitor
+{
+    // Implementations for ClassFileVisitor.
+
+    public void visitProgramClassFile(ProgramClassFile programClassFile)
+    {
+        // Make the class public, if it is package visible.
+        makePackageVisible(programClassFile);
+
+        // Make package visible class members public.
+        programClassFile.fieldsAccept(this);
+        programClassFile.methodsAccept(this);
+    }
+
+
+    public void visitLibraryClassFile(LibraryClassFile libraryClassFile) {}
+
+
+    // Implementations for MemberInfoVisitor.
+
+    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+    {
+        makePackageVisible(programFieldInfo);
+    }
+
+    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+    {
+        makePackageVisible(programMethodInfo);
+    }
+
+
+    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+
+
+    // Small utility methods.
+
+    /**
+     * Makes the given class file public, if it is package visible.
+     */
+    private void makePackageVisible(ProgramClassFile programClassFile)
+    {
+        if (isPackageVisible(programClassFile.u2accessFlags))
+        {
+            programClassFile.u2accessFlags = makePublic(programClassFile.u2accessFlags);
+        }
+    }
+
+    /**
+     * Makes the given class member public, if it is package visible.
+     */
+    private void makePackageVisible(ProgramMemberInfo programMemberInfo)
+    {
+        if (isPackageVisible(programMemberInfo.u2accessFlags))
+        {
+            programMemberInfo.u2accessFlags = makePublic(programMemberInfo.u2accessFlags);
+        }
+    }
+
+
+    /**
+     * Returns whether the given access flags specify a package visible class
+     * or class member (including public or protected access).
+     */
+    private boolean isPackageVisible(int accessFlags)
+    {
+        return AccessUtil.accessLevel(accessFlags) >= AccessUtil.PACKAGE_VISIBLE;
+    }
+
+
+    /**
+     * Returns the given access flags, modified such that the class or class
+     * member becomes public.
+     */
+    private int makePublic(int accessFlags)
+    {
+        return AccessUtil.replaceAccessFlags(accessFlags,
+                                             ClassConstants.INTERNAL_ACC_PUBLIC);
+    }
+}
diff --git a/src/proguard/obfuscate/ClassFileRenamer.java b/src/proguard/obfuscate/ClassFileRenamer.java
index 7e23ca2..0a3c856 100644
--- a/src/proguard/obfuscate/ClassFileRenamer.java
+++ b/src/proguard/obfuscate/ClassFileRenamer.java
@@ -1,36 +1,33 @@
-/* $Id: ClassFileRenamer.java,v 1.37 2004/11/20 15:41:24 eric Exp $
+/* $Id: ClassFileRenamer.java,v 1.42 2005/06/25 22:06:31 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
- * This program is free software; you can redistribute it and/or modify it
+ * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
  * Software Foundation; either version 2 of the License, or (at your option)
  * any later version.
  *
- * This program is distributed in the hope that it will be useful, but WITHOUT
+ * This library 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 General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
+ * with this library; if not, write to the Free Software Foundation, Inc.,
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 package proguard.obfuscate;
 
 import proguard.classfile.*;
-import proguard.classfile.attribute.*;
-import proguard.classfile.attribute.annotation.*;
-import proguard.classfile.util.*;
+import proguard.classfile.editor.ConstantPoolEditor;
 import proguard.classfile.visitor.*;
 
 /**
  * This <code>ClassFileVisitor</code> renames the class names and class member
  * names of the classes it visits, using names previously determined by the
- * obfuscator. It can also make package visible classes and class members public,
- * and it can replace the source file attribute by a given constant string.
+ * obfuscator.
  *
  * @see ClassFileObfuscator
  *
@@ -39,140 +36,88 @@ import proguard.classfile.visitor.*;
 public class ClassFileRenamer
   implements ClassFileVisitor,
              MemberInfoVisitor,
-             CpInfoVisitor,
-             AttrInfoVisitor,
-             LocalVariableInfoVisitor,
-             LocalVariableTypeInfoVisitor,
-             AnnotationVisitor,
-             ElementValueVisitor
+             CpInfoVisitor
 {
-    private MyNameAndTypeRenamer nameAndTypeRenamer = new MyNameAndTypeRenamer();
-
-    private boolean openUpPackages;
-    private String  newSourceFileAttribute;
-
-
-    /**
-     * Creates a new ClassFileRenamer.
-     * @param openUpPackages         specifies whether to make package visible
-     *                               classes and class members public.
-     * @param newSourceFileAttribute the new string to be put in the source file
-     *                               attribute (if present) of the visited classes,
-     *                               or <code>null</code> to leave it unchanged.
-     */
-    public ClassFileRenamer(boolean openUpPackages,
-                            String  newSourceFileAttribute)
-    {
-        this.openUpPackages         = openUpPackages;
-        this.newSourceFileAttribute = newSourceFileAttribute;
-    }
+    private ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor();
 
 
     // Implementations for ClassFileVisitor.
 
     public void visitProgramClassFile(ProgramClassFile programClassFile)
     {
-        // Rename class members.
+        // Rename this class.
+        programClassFile.constantPoolEntryAccept(programClassFile.u2thisClass, this);
+
+        // Rename the class members.
         programClassFile.fieldsAccept(this);
         programClassFile.methodsAccept(this);
+    }
 
-        // Rename NameAndTypeCpInfo type references in the constant pool.
-        programClassFile.constantPoolEntriesAccept(nameAndTypeRenamer);
-
-        // Rename class references and class member references in the constant pool.
-        programClassFile.constantPoolEntriesAccept(this);
 
-        // Make package visible classes public, if specified.
-        if (openUpPackages && isPackageVisible(programClassFile.u2accessFlags))
-        {
-            programClassFile.u2accessFlags = makePublic(programClassFile.u2accessFlags);
-        }
+    public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+    {
+        libraryClassFile.thisClassName = ClassFileObfuscator.newClassName(libraryClassFile);
 
-        programClassFile.attributesAccept(this);
+        // Rename the class members.
+        libraryClassFile.fieldsAccept(this);
+        libraryClassFile.methodsAccept(this);
     }
 
 
-    public void visitLibraryClassFile(LibraryClassFile libraryClassFile) {}
-
-
     // Implementations for MemberInfoVisitor.
 
     public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
     {
-        visitMemberInfo(programClassFile, programFieldInfo);
+        renameProgramMemberInfo(programClassFile, programFieldInfo);
     }
 
+
     public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
-        visitMemberInfo(programClassFile, programMethodInfo);
+        renameProgramMemberInfo(programClassFile, programMethodInfo);
+    }
+
+
+    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+    {
+        renameLibraryMemberInfo(libraryClassFile, libraryFieldInfo);
     }
 
-    private void visitMemberInfo(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+
+    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
     {
-        String name       = programMemberInfo.getName(programClassFile);
-        String descriptor = programMemberInfo.getDescriptor(programClassFile);
+        renameLibraryMemberInfo(libraryClassFile, libraryMethodInfo);
+    }
+
 
-        // The new name is stored with the class member.
+    /**
+     * Renames the given program member info, if necessary.
+     */
+    private void renameProgramMemberInfo(ProgramClassFile  programClassFile,
+                                         ProgramMemberInfo programMemberInfo)
+    {
+        // Has the class member name changed?
+        String name    = programMemberInfo.getName(programClassFile);
         String newName = MemberInfoObfuscator.newMemberName(programMemberInfo);
         if (newName != null &&
             !newName.equals(name))
         {
             programMemberInfo.u2nameIndex =
-                createUtf8CpInfo(programClassFile, newName);
-        }
-
-        // Compute the new descriptor.
-        String newDescriptor = newDescriptor(programMemberInfo.getDescriptor(programClassFile),
-                                             programMemberInfo.referencedClassFiles);
-        if (newDescriptor != null)
-        {
-            programMemberInfo.u2descriptorIndex =
-                createUtf8CpInfo(programClassFile, newDescriptor);
-        }
-
-        // Make package visible class members public, if specified.
-        if (openUpPackages && isPackageVisible(programMemberInfo.u2accessFlags))
-        {
-            programMemberInfo.u2accessFlags = makePublic(programMemberInfo.u2accessFlags);
+                constantPoolEditor.addUtf8CpInfo(programClassFile, newName);
         }
     }
 
 
-    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
-    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
-
-
     /**
-     * This CpInfoVisitor renames all type elements in all NameAndTypeCpInfo
-     * constant pool entries it visits.
+     * Renames the given library member info.
      */
-    private class MyNameAndTypeRenamer
-       implements CpInfoVisitor
+    private void renameLibraryMemberInfo(LibraryClassFile  libraryClassFile,
+                                         LibraryMemberInfo libraryMemberInfo)
     {
-        // Implementations for CpInfoVisitor.
-
-        public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
-        public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
-        public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
-        public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
-        public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
-        public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
-        public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo) {}
-        public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
-        public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
-        public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo) {}
-
-
-        public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
+        String newName = MemberInfoObfuscator.newMemberName(libraryMemberInfo);
+        if (newName != null)
         {
-            // Compute the new descriptor.
-            String newDescriptor = newDescriptor(nameAndTypeCpInfo.getType(classFile),
-                                                 nameAndTypeCpInfo.referencedClassFiles);
-            if (newDescriptor != null)
-            {
-                nameAndTypeCpInfo.u2descriptorIndex =
-                    createUtf8CpInfo((ProgramClassFile)classFile, newDescriptor);
-            }
+            libraryMemberInfo.name = newName;
         }
     }
 
@@ -183,534 +128,24 @@ public class ClassFileRenamer
     public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
     public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
     public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
-    public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+    public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+    public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
+    public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
+    public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo) {}
     public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
-
-
-    public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
-    {
-        // If the string is being used in a Class.forName construct, the new
-        // class name can be retrieved from the referenced ClassFile.
-        String newClassName = newClassName(stringCpInfo.getString(classFile),
-                                           stringCpInfo.referencedClassFile);
-        if (newClassName != null)
-        {
-            String newExternalClassName = ClassUtil.externalClassName(newClassName);
-
-            // Refer to a new Utf8 entry.
-            stringCpInfo.u2stringIndex =
-                createUtf8CpInfo((ProgramClassFile)classFile, newExternalClassName);
-        }
-    }
+    public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
 
 
     public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
     {
-        // Compute the new class name (or type).
-        String newClassName = newClassName(classCpInfo.getName(classFile),
-                                           classCpInfo.referencedClassFile);
-        if (newClassName != null)
+        // Update the Class entry if required.
+        String newName = ClassFileObfuscator.newClassName(classFile);
+        if (newName != null)
         {
             // Refer to a new Utf8 entry.
             classCpInfo.u2nameIndex =
-                createUtf8CpInfo((ProgramClassFile)classFile, newClassName);
-        }
-    }
-
-
-    public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
-    {
-        visitRefCpInfo(classFile, fieldrefCpInfo);
-    }
-
-
-    public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
-    {
-        visitRefCpInfo(classFile, interfaceMethodrefCpInfo);
-    }
-
-
-    public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
-    {
-        visitRefCpInfo(classFile, methodrefCpInfo);
-    }
-
-
-    private void visitRefCpInfo(ClassFile classFile, RefCpInfo refCpInfo)
-    {
-        // Compute the new class member name.
-        String newMemberName = newMemberName(refCpInfo.referencedMemberInfo);
-
-        if (newMemberName != null)
-        {
-            // Refer to a new NameAndType entry.
-            refCpInfo.u2nameAndTypeIndex =
-                createNameAndTypeCpInfo((ProgramClassFile)classFile,
-                                        newMemberName,
-                                        refCpInfo.getType(classFile));
-        }
-    }
-
-
-    // Implementations for AttrInfoVisitor.
-
-    public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
-    public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
-    public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
-    public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
-    public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo) {}
-    public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
-    public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
-    public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
-
-
-    public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo)
-    {
-        // Compute the new class member name.
-        String newMethodName = newMemberName(enclosingMethodAttrInfo.referencedMethodInfo);
-
-        if (newMethodName != null)
-        {
-            // Refer to a new NameAndType entry.
-            enclosingMethodAttrInfo.u2nameAndTypeIndex =
-                createNameAndTypeCpInfo((ProgramClassFile)classFile,
-                                        newMethodName,
-                                        enclosingMethodAttrInfo.getType(classFile));
-        }
-    }
-
-
-    public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo)
-    {
-        // Rename the types of the local variables.
-        localVariableTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
-    }
-
-
-    public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo)
-    {
-        // Rename the signatures of the local variables.
-        localVariableTypeTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
-    }
-
-
-    public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo)
-    {
-        // Rename the source file attribute, if specified.
-        if (newSourceFileAttribute != null)
-        {
-            sourceFileAttrInfo.u2sourceFileIndex =
-                createUtf8CpInfo((ProgramClassFile)classFile, newSourceFileAttribute);
-        }
-    }
-
-
-    public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo)
-    {
-        // Rename the source file attribute, if specified.
-        if (newSourceFileAttribute != null)
-        {
-            sourceDirAttrInfo.u2sourceDirIndex =
-                createUtf8CpInfo((ProgramClassFile)classFile, newSourceFileAttribute);
-        }
-    }
-
-
-    public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo)
-    {
-        // Compute the new signature.
-        String newSignature = newDescriptor(classFile.getCpString(signatureAttrInfo.u2signatureIndex),
-                                            signatureAttrInfo.referencedClassFiles);
-        if (newSignature != null)
-        {
-            signatureAttrInfo.u2signatureIndex =
-                createUtf8CpInfo((ProgramClassFile)classFile, newSignature);
-        }
-    }
-
-
-    public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo)
-    {
-        // Rename the annotations.
-        runtimeVisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
-    }
-
-
-    public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo)
-    {
-        // Rename the annotations.
-        runtimeInvisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
-    }
-
-
-    public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo)
-    {
-        // Rename the annotations.
-        runtimeVisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
-    }
-
-
-    public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo)
-    {
-        // Rename the annotations.
-        runtimeInvisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
-    }
-
-
-    public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo)
-    {
-        // Rename the annotation.
-        annotationDefaultAttrInfo.defaultValueAccept(classFile, this);
-    }
-
-
-    // Implementations for LocalVariableInfoVisitor.
-
-    public void visitLocalVariableInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableInfo localVariableInfo)
-    {
-        // Compute the new descriptor.
-        String newDescriptor = newClassName(classFile.getCpString(localVariableInfo.u2descriptorIndex),
-                                            localVariableInfo.referencedClassFile);
-        if (newDescriptor != null)
-        {
-            // Refer to a new Utf8 entry.
-            localVariableInfo.u2descriptorIndex =
-                createUtf8CpInfo((ProgramClassFile)classFile, newDescriptor);
-        }
-    }
-
-
-    // Implementations for LocalVariableTypeInfoVisitor.
-
-    public void visitLocalVariableTypeInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeInfo localVariableTypeInfo)
-    {
-        // Compute the new signature.
-        String newSignature = newDescriptor(classFile.getCpString(localVariableTypeInfo.u2signatureIndex),
-                                            localVariableTypeInfo.referencedClassFiles);
-        if (newSignature != null)
-        {
-            localVariableTypeInfo.u2signatureIndex =
-                createUtf8CpInfo((ProgramClassFile)classFile, newSignature);
-        }
-    }
-
-
-    // Implementations for AnnotationVisitor.
-
-    public void visitAnnotation(ClassFile classFile, Annotation annotation)
-    {
-        // Compute the new type name.
-        String newTypeName = newDescriptor(classFile.getCpString(annotation.u2typeIndex),
-                                           annotation.referencedClassFiles);
-        if (newTypeName != null)
-        {
-            // Refer to a new Utf8 entry.
-            annotation.u2typeIndex =
-                createUtf8CpInfo((ProgramClassFile)classFile, newTypeName);
-        }
-
-        // Rename the element values.
-        annotation.elementValuesAccept(classFile, this);
-    }
-
-
-    // Implementations for ElementValueVisitor.
-
-    public void visitConstantElementValue(ClassFile classFile, Annotation annotation, ConstantElementValue constantElementValue)
-    {
-        renameElementValue(classFile, constantElementValue);
-    }
-
-
-    public void visitEnumConstantElementValue(ClassFile classFile, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
-    {
-        renameElementValue(classFile, enumConstantElementValue);
-
-        // Compute the new type name.
-        String newTypeName = newDescriptor(classFile.getCpString(enumConstantElementValue.u2typeNameIndex),
-                                           enumConstantElementValue.referencedClassFiles);
-        if (newTypeName != null)
-        {
-            // Refer to a new Utf8 entry.
-            enumConstantElementValue.u2typeNameIndex =
-                createUtf8CpInfo((ProgramClassFile)classFile, newTypeName);
-        }
-    }
-
-
-    public void visitClassElementValue(ClassFile classFile, Annotation annotation, ClassElementValue classElementValue)
-    {
-        renameElementValue(classFile, classElementValue);
-
-        // Compute the new class name.
-        String newClassName = newDescriptor(classFile.getCpString(classElementValue.u2classInfoIndex),
-                                            classElementValue.referencedClassFiles);
-
-        if (newClassName != null)
-        {
-            // Refer to a new Utf8 entry.
-            classElementValue.u2classInfoIndex =
-                createUtf8CpInfo((ProgramClassFile)classFile, newClassName);
-        }
-    }
-
-
-    public void visitAnnotationElementValue(ClassFile classFile, Annotation annotation, AnnotationElementValue annotationElementValue)
-    {
-        renameElementValue(classFile, annotationElementValue);
-
-        // Rename the annotation.
-        annotationElementValue.annotationAccept(classFile, this);
-    }
-
-
-    public void visitArrayElementValue(ClassFile classFile, Annotation annotation, ArrayElementValue arrayElementValue)
-    {
-        renameElementValue(classFile, arrayElementValue);
-
-        // Rename the element values.
-        arrayElementValue.elementValuesAccept(classFile, annotation, this);
-    }
-
-
-    /**
-     * Renames the method reference of the element value, if any.
-     */
-    public void renameElementValue(ClassFile classFile, ElementValue elementValue)
-    {
-        // Compute the new class member name.
-        String newMethodName = newMemberName(elementValue.referencedMethodInfo);
-
-        if (newMethodName != null)
-        {
-            // Refer to a new NameAndType entry.
-            elementValue.u2elementName =
-                createUtf8CpInfo((ProgramClassFile)classFile, newMethodName);
-        }
-    }
-
-
-    // Small utility methods.
-
-    /**
-     * Finds or creates a NameAndTypeCpInfo constant pool entry with the given
-     * name and type, in the given class file.
-     * @return the constant pool index of the NameAndTypeCpInfo.
-     */
-    private int createNameAndTypeCpInfo(ProgramClassFile programClassFile,
-                                        String           name,
-                                        String           type)
-    {
-        CpInfo[] constantPool        = programClassFile.constantPool;
-        int      u2constantPoolCount = programClassFile.u2constantPoolCount;
-
-        // Pick up the right list of referenced class files, in case we need to
-        // create a new NameAndTypeCpInfo.
-        ClassFile[] referencedClassFiles = null;
-
-        // Check if there is a NameAndTypeCpInfo with the given name and type already.
-        for (int index = 1; index < u2constantPoolCount; index++)
-        {
-            CpInfo cpInfo = constantPool[index];
-
-            if (cpInfo != null &&
-                cpInfo.getTag() == ClassConstants.CONSTANT_NameAndType)
-            {
-                NameAndTypeCpInfo nameAndTypeCpInfo = (NameAndTypeCpInfo)cpInfo;
-                if (nameAndTypeCpInfo.getType(programClassFile).equals(type))
-                {
-                    if (nameAndTypeCpInfo.getName(programClassFile).equals(name))
-                    {
-                        return index;
-                    }
-
-                    referencedClassFiles = nameAndTypeCpInfo.referencedClassFiles;
-                }
-            }
-        }
-
-        int u2nameIndex       = createUtf8CpInfo(programClassFile, name);
-        int u2descriptorIndex = createUtf8CpInfo(programClassFile, type);
-
-        return addCpInfo(programClassFile, new NameAndTypeCpInfo(u2nameIndex,
-                                                                 u2descriptorIndex,
-                                                                 referencedClassFiles));
-    }
-
-
-    /**
-     * Finds or creates an Utf8CpInfo constant pool entry for the given string,
-     * in the given class file.
-     * @return the constant pool index of the Utf8CpInfo.
-     */
-    private int createUtf8CpInfo(ProgramClassFile programClassFile, String string)
-    {
-        CpInfo[] constantPool        = programClassFile.constantPool;
-        int      u2constantPoolCount = programClassFile.u2constantPoolCount;
-
-        // Check if there is a Utf8CpInfo with the given string already.
-        for (int index = 1; index < u2constantPoolCount; index++)
-        {
-            CpInfo cpInfo = constantPool[index];
-
-            if (cpInfo != null &&
-                cpInfo.getTag() == ClassConstants.CONSTANT_Utf8)
-            {
-                Utf8CpInfo utf8CpInfo = (Utf8CpInfo)cpInfo;
-                if (utf8CpInfo.getString().equals(string))
-                {
-                    return index;
-                }
-            }
+                constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
+                                                 newName);
         }
-
-        return addCpInfo(programClassFile, new Utf8CpInfo(string));
-    }
-
-
-    /**
-     * Adds a given constant pool entry to the end of the constant pool.
-     * @return the constant pool index for the added entry.
-     */
-    private int addCpInfo(ProgramClassFile programClassFile, CpInfo cpInfo)
-    {
-        CpInfo[] constantPool        = programClassFile.constantPool;
-        int      u2constantPoolCount = programClassFile.u2constantPoolCount;
-
-        // Make sure there is enough space for another constant pool entry.
-        if (u2constantPoolCount == constantPool.length)
-        {
-            programClassFile.constantPool = new CpInfo[u2constantPoolCount+1];
-            System.arraycopy(constantPool, 0,
-                             programClassFile.constantPool, 0,
-                             u2constantPoolCount);
-            constantPool = programClassFile.constantPool;
-
-        }
-
-        // Create a new Utf8CpInfo for the given string.
-        constantPool[programClassFile.u2constantPoolCount++] = cpInfo;
-
-        return u2constantPoolCount;
-    }
-
-
-    /**
-     * Returns the new descriptor based on the given descriptor and the new
-     * names of the given referenced class files.
-     */
-    private String newDescriptor(String      descriptor,
-                                 ClassFile[] referencedClassFiles)
-    {
-        // If there are no referenced classes, the descriptor doesn't change.
-        if (referencedClassFiles == null)
-        {
-            return null;
-        }
-
-        // Unravel and reconstruct the class elements of the descriptor.
-        DescriptorClassEnumeration descriptorClassEnumeration =
-            new DescriptorClassEnumeration(descriptor);
-
-        String newDescriptor = descriptorClassEnumeration.nextFluff();
-
-        int index = 0;
-        while (descriptorClassEnumeration.hasMoreClassNames())
-        {
-            String className = descriptorClassEnumeration.nextClassName();
-            String fluff     = descriptorClassEnumeration.nextFluff();
-
-            String newClassName = newClassName(className,
-                                               referencedClassFiles[index++]);
-
-            // Fall back on the original class name if there is no new name.
-            if (newClassName == null)
-            {
-                newClassName = className;
-            }
-
-            newDescriptor = newDescriptor + newClassName + fluff;
-        }
-
-        // If the descriptor hasn't changed after all, just return null.
-        if (descriptor.equals(newDescriptor))
-        {
-            return null;
-        }
-
-        return newDescriptor;
-    }
-
-
-    /**
-     * Returns the new class name based on the given class name and the new
-     * name of the given referenced class file. Class names of array types
-     * are handled properly.
-     */
-    private String newClassName(String    className,
-                                ClassFile referencedClassFile)
-    {
-        // If there is no referenced class, the descriptor doesn't change.
-        if (referencedClassFile == null)
-        {
-            return null;
-        }
-
-        String newClassName =
-            ClassFileObfuscator.newClassName(referencedClassFile);
-
-        // If there is no new class name, the descriptor doesn't change.
-        if (newClassName == null)
-        {
-            return null;
-        }
-
-        // Is it an array type?
-        if (className.charAt(0) == ClassConstants.INTERNAL_TYPE_ARRAY)
-        {
-            // Add the array prefixes and suffix "[L...;".
-            newClassName =
-                 className.substring(0, className.indexOf(ClassConstants.INTERNAL_TYPE_CLASS_START)+1) +
-                 newClassName +
-                 ClassConstants.INTERNAL_TYPE_CLASS_END;
-        }
-
-        return newClassName;
-    }
-
-
-    /**
-     * Returns the new class member name based on the given referenced class
-     * member.
-     */
-    private String newMemberName(MemberInfo referencedMemberInfo)
-    {
-        if (referencedMemberInfo == null)
-        {
-            return null;
-        }
-
-        return MemberInfoObfuscator.newMemberName(referencedMemberInfo);
-    }
-
-
-    /**
-     * Returns whether the given access flags specify a package visible class
-     * or class member (including public or protected access).
-     */
-    private boolean isPackageVisible(int accessFlags)
-    {
-        return AccessUtil.accessLevel(accessFlags) >= AccessUtil.PACKAGE_VISIBLE;
-    }
-
-
-    /**
-     * Returns the given access flags, modified such that the class or class
-     * member becomes public.
-     */
-    private int makePublic(int accessFlags)
-    {
-        return AccessUtil.replaceAccessFlags(accessFlags,
-                                             ClassConstants.INTERNAL_ACC_PUBLIC);
     }
 }
diff --git a/src/proguard/obfuscate/ReadNameFactory.java b/src/proguard/obfuscate/DictionaryNameFactory.java
similarity index 87%
rename from src/proguard/obfuscate/ReadNameFactory.java
rename to src/proguard/obfuscate/DictionaryNameFactory.java
index 97ca12d..4ef37eb 100644
--- a/src/proguard/obfuscate/ReadNameFactory.java
+++ b/src/proguard/obfuscate/DictionaryNameFactory.java
@@ -1,8 +1,8 @@
-/* $Id: ReadNameFactory.java,v 1.2 2004/11/20 15:41:24 eric Exp $
+/* $Id: DictionaryNameFactory.java,v 1.3 2005/06/11 13:13:15 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -30,7 +30,7 @@ import java.util.*;
  *
  * @author Eric Lafortune
  */
-public class ReadNameFactory implements NameFactory
+public class DictionaryNameFactory implements NameFactory
 {
     private static final char COMMENT_CHARACTER = '#';
 
@@ -42,17 +42,17 @@ public class ReadNameFactory implements NameFactory
 
 
     /**
-     * Creates a new <code>ReadNameFactory</code>.
-     * @param fileName    the name of the file from which the names can be read.
+     * Creates a new <code>DictionaryNameFactory</code>.
+     * @param file        the file from which the names can be read.
      * @param nameFactory the name factory from which names will be retrieved
      *                    if the list of read names has been exhausted.
      */
-    public ReadNameFactory(String      fileName,
-                           NameFactory nameFactory) throws IOException
+    public DictionaryNameFactory(File        file,
+                                 NameFactory nameFactory) throws IOException
     {
         this.nameFactory = nameFactory;
 
-        Reader reader = new FileReader(fileName);
+        Reader reader = new FileReader(file);
 
         try
         {
@@ -156,7 +156,8 @@ public class ReadNameFactory implements NameFactory
     {
         try
         {
-            ReadNameFactory factory = new ReadNameFactory(args[0], new SimpleNameFactory());
+            DictionaryNameFactory factory =
+                new DictionaryNameFactory(new File(args[0]), new SimpleNameFactory());
 
             for (int counter = 0; counter < 50; counter++)
             {
diff --git a/src/proguard/classfile/visitor/AllCpInfoVisitor.java b/src/proguard/obfuscate/MapCleaner.java
similarity index 65%
copy from src/proguard/classfile/visitor/AllCpInfoVisitor.java
copy to src/proguard/obfuscate/MapCleaner.java
index d23a284..a123e76 100644
--- a/src/proguard/classfile/visitor/AllCpInfoVisitor.java
+++ b/src/proguard/obfuscate/MapCleaner.java
@@ -1,8 +1,8 @@
-/* $Id: AllCpInfoVisitor.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: MapCleaner.java,v 1.3 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -18,25 +18,30 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-package proguard.classfile.visitor;
+package proguard.obfuscate;
 
 import proguard.classfile.*;
+import proguard.classfile.visitor.ClassFileVisitor;
 
+import java.util.Map;
 
 /**
- * This ClassFileVisitor lets a given CpInfoVisitor visit all constant pool
- * entries of the program class files it visits.
+ * This ClassFileVisitor clears a given map whenever it visits a class file.
  *
  * @author Eric Lafortune
  */
-public class AllCpInfoVisitor implements ClassFileVisitor
+public class MapCleaner implements ClassFileVisitor
 {
-    private CpInfoVisitor cpInfoVisitor;
+    private Map map;
 
 
-    public AllCpInfoVisitor(CpInfoVisitor cpInfoVisitor)
+    /**
+     * Creates a new MapCleaner.
+     * @param map the map to be cleared.
+     */
+    public MapCleaner(Map map)
     {
-        this.cpInfoVisitor = cpInfoVisitor;
+        this.map = map;
     }
 
 
@@ -44,9 +49,12 @@ public class AllCpInfoVisitor implements ClassFileVisitor
 
     public void visitProgramClassFile(ProgramClassFile programClassFile)
     {
-        programClassFile.constantPoolEntriesAccept(cpInfoVisitor);
+        map.clear();
     }
 
 
-    public void visitLibraryClassFile(LibraryClassFile libraryClassFile) {}
+    public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+    {
+        map.clear();
+    }
 }
diff --git a/src/proguard/obfuscate/MappingKeeper.java b/src/proguard/obfuscate/MappingKeeper.java
index 69494a9..6c77290 100644
--- a/src/proguard/obfuscate/MappingKeeper.java
+++ b/src/proguard/obfuscate/MappingKeeper.java
@@ -1,8 +1,8 @@
-/* $Id: MappingKeeper.java,v 1.8 2004/08/15 12:39:30 eric Exp $
+/* $Id: MappingKeeper.java,v 1.10 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -88,7 +88,7 @@ public class MappingKeeper implements MappingProcessor
             if (fieldInfo != null)
             {
                 // Make sure the mapping name will be kept.
-                MemberInfoObfuscator.setNewMemberName(fieldInfo, newFieldName);
+                MemberInfoObfuscator.setFixedNewMemberName(fieldInfo, newFieldName);
             }
         }
     }
@@ -112,7 +112,7 @@ public class MappingKeeper implements MappingProcessor
             if (methodInfo != null)
             {
                 // Make sure the mapping name will be kept.
-                MemberInfoObfuscator.setNewMemberName(methodInfo, newMethodName);
+                MemberInfoObfuscator.setFixedNewMemberName(methodInfo, newMethodName);
             }
         }
     }
diff --git a/src/proguard/obfuscate/MappingPrinter.java b/src/proguard/obfuscate/MappingPrinter.java
index dd38362..c7639fd 100644
--- a/src/proguard/obfuscate/MappingPrinter.java
+++ b/src/proguard/obfuscate/MappingPrinter.java
@@ -1,8 +1,8 @@
-/* $Id: MappingPrinter.java,v 1.15 2004/08/15 12:39:30 eric Exp $
+/* $Id: MappingPrinter.java,v 1.19 2005/06/25 22:06:06 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -41,9 +41,6 @@ public class MappingPrinter
 {
     private PrintStream ps;
 
-    // A field to remember the class name, if a header is needed for class members.
-    private String className;
-
 
     /**
      * Creates a new MappingPrinter that prints to <code>System.out</code>.
@@ -68,19 +65,13 @@ public class MappingPrinter
 
     public void visitProgramClassFile(ProgramClassFile programClassFile)
     {
-        className = programClassFile.getName();
-
-        String newClassName = ClassFileObfuscator.newClassName(programClassFile);
-
-        if (newClassName != null)
-        {
-            ps.println(ClassUtil.externalClassName(className) +
-                       " -> " +
-                       ClassUtil.externalClassName(newClassName) +
-                       ":");
+        String name    = programClassFile.getName();
+        String newName = ClassFileObfuscator.newClassName(programClassFile);
 
-            className = null;
-        }
+        ps.println(ClassUtil.externalClassName(name) +
+                   " -> " +
+                   ClassUtil.externalClassName(newName) +
+                   ":");
 
         // Print out the class members.
         programClassFile.fieldsAccept(this);
@@ -97,41 +88,44 @@ public class MappingPrinter
 
     public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
     {
-        String newMemberName = MemberInfoObfuscator.newMemberName(programFieldInfo);
-
-        if (newMemberName != null)
+        String newName = MemberInfoObfuscator.newMemberName(programFieldInfo);
+        if (newName != null)
         {
-            printClassNameHeader();
-
             ps.println("    " +
-                       lineNumberRange(programClassFile, programFieldInfo) +
+                       //lineNumberRange(programClassFile, programFieldInfo) +
                        ClassUtil.externalFullFieldDescription(
                            0,
                            programFieldInfo.getName(programClassFile),
                            programFieldInfo.getDescriptor(programClassFile)) +
                        " -> " +
-                       newMemberName);
+                       newName);
         }
     }
 
 
     public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
-      String newMemberName = MemberInfoObfuscator.newMemberName(programMethodInfo);
-
-      if (newMemberName != null)
+        // Special cases: <clinit> and <init> are always kept unchanged.
+        // We can ignore them here.
+        String name = programMethodInfo.getName(programClassFile);
+        if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) ||
+            name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
         {
-            printClassNameHeader();
+            return;
+        }
 
+        String newName = MemberInfoObfuscator.newMemberName(programMethodInfo);
+        if (newName != null)
+        {
             ps.println("    " +
                        lineNumberRange(programClassFile, programMethodInfo) +
                        ClassUtil.externalFullMethodDescription(
-                       programClassFile.getName(),
-                       0,
-                       programMethodInfo.getName(programClassFile),
-                       programMethodInfo.getDescriptor(programClassFile)) +
+                           programClassFile.getName(),
+                           0,
+                           programMethodInfo.getName(programClassFile),
+                           programMethodInfo.getDescriptor(programClassFile)) +
                        " -> " +
-                       newMemberName);
+                       newName);
         }
     }
 
@@ -143,20 +137,6 @@ public class MappingPrinter
     // Small utility methods.
 
     /**
-     * Prints the class name field. The field is then cleared, so it is not
-     * printed again.
-     */
-    private void printClassNameHeader()
-    {
-        if (className != null)
-        {
-            ps.println(ClassUtil.externalClassName(className) + ":");
-            className = null;
-        }
-    }
-
-
-    /**
      * Returns the line number range of the given class member, followed by a
      * colon, or just an empty String if no range is available.
      */
diff --git a/src/proguard/obfuscate/MappingProcessor.java b/src/proguard/obfuscate/MappingProcessor.java
index a37df97..e700036 100644
--- a/src/proguard/obfuscate/MappingProcessor.java
+++ b/src/proguard/obfuscate/MappingProcessor.java
@@ -1,8 +1,8 @@
-/* $Id: MappingProcessor.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+/* $Id: MappingProcessor.java,v 1.5 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/obfuscate/MappingReader.java b/src/proguard/obfuscate/MappingReader.java
index bad1218..4b358fd 100644
--- a/src/proguard/obfuscate/MappingReader.java
+++ b/src/proguard/obfuscate/MappingReader.java
@@ -1,8 +1,8 @@
-/* $Id: MappingReader.java,v 1.8 2004/08/15 12:39:30 eric Exp $
+/* $Id: MappingReader.java,v 1.10 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -31,12 +31,12 @@ import java.io.*;
  */
 public class MappingReader
 {
-    private String mappingFileName;
+    private File mappingFile;
 
 
-    public MappingReader(String mappingFileName)
+    public MappingReader(File mappingFile)
     {
-        this.mappingFileName = mappingFileName;
+        this.mappingFile = mappingFile;
     }
 
 
@@ -52,7 +52,7 @@ public class MappingReader
         {
             reader = new LineNumberReader(
                      new BufferedReader(
-                     new FileReader(mappingFileName)));
+                     new FileReader(mappingFile)));
 
             String className = null;
 
diff --git a/src/proguard/classfile/attribute/AllAttrInfoVisitor.java b/src/proguard/obfuscate/MemberInfoNameCleaner.java
similarity index 62%
copy from src/proguard/classfile/attribute/AllAttrInfoVisitor.java
copy to src/proguard/obfuscate/MemberInfoNameCleaner.java
index ca8582e..8e563dc 100644
--- a/src/proguard/classfile/attribute/AllAttrInfoVisitor.java
+++ b/src/proguard/obfuscate/MemberInfoNameCleaner.java
@@ -1,8 +1,8 @@
-/* $Id: AllAttrInfoVisitor.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: MemberInfoNameCleaner.java,v 1.3 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2003 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -18,51 +18,46 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-package proguard.classfile.attribute;
+package proguard.obfuscate;
 
 import proguard.classfile.*;
-import proguard.classfile.visitor.*;
+import proguard.classfile.visitor.MemberInfoVisitor;
 
+import java.util.*;
 
 /**
- * This MemberInfoVisitor lets a given AttrInfoVisitor visit all AttrInfo
- * objects of the program class members it visits.
+ * This <code>MemberInfoVisitor</code> clears the new names of the class members
+ * that it visits.
+ *
+ * @see MemberInfoLinker
+ * @see MemberInfoObfuscator
  *
  * @author Eric Lafortune
  */
-public class AllAttrInfoVisitor implements MemberInfoVisitor
+public class MemberInfoNameCleaner implements MemberInfoVisitor
 {
-    private AttrInfoVisitor attrInfoVisitor;
-
-
-    public AllAttrInfoVisitor(AttrInfoVisitor attrInfoVisitor)
-    {
-        this.attrInfoVisitor = attrInfoVisitor;
-    }
-
-
     // Implementations for MemberInfoVisitor.
 
     public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
     {
-        programFieldInfo.attributesAccept(programClassFile, attrInfoVisitor);
+        MemberInfoObfuscator.setNewMemberName(programFieldInfo, null);
     }
 
 
     public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
-        programMethodInfo.attributesAccept(programClassFile, attrInfoVisitor);
+        MemberInfoObfuscator.setNewMemberName(programMethodInfo, null);
     }
 
 
     public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
     {
-        // Library class file fields don't have attributes.
+        MemberInfoObfuscator.setNewMemberName(libraryFieldInfo, null);
     }
 
 
     public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
     {
-        // Library class file methods don't have attributes.
+        MemberInfoObfuscator.setNewMemberName(libraryMethodInfo, null);
     }
 }
diff --git a/src/proguard/obfuscate/MemberInfoNameCollector.java b/src/proguard/obfuscate/MemberInfoNameCollector.java
new file mode 100644
index 0000000..ab887b3
--- /dev/null
+++ b/src/proguard/obfuscate/MemberInfoNameCollector.java
@@ -0,0 +1,132 @@
+/* $Id: MemberInfoNameCollector.java,v 1.3 2005/06/11 13:21:35 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.*;
+
+import java.io.IOException;
+import java.util.*;
+
+
+/**
+ * This MemberInfoVisitor collects all new (obfuscation) names of the members
+ * that it visits.
+ *
+ * @see MemberInfoLinker
+ * @see MemberInfoObfuscator
+ *
+ * @author Eric Lafortune
+ */
+public class MemberInfoNameCollector implements MemberInfoVisitor
+{
+    private boolean allowAggressiveOverloading;
+    private Map     descriptorMap;
+
+
+    /**
+     * Creates a new MemberInfoNameCollector.
+     * @param allowAggressiveOverloading a flag that specifies whether class
+     *                                   members can be overloaded aggressively.
+     * @param descriptorMap              the map of descriptors to
+     *                                   [new name - old name] maps.
+     */
+    public MemberInfoNameCollector(boolean allowAggressiveOverloading,
+                                   Map     descriptorMap)
+    {
+        this.allowAggressiveOverloading = allowAggressiveOverloading;
+        this.descriptorMap              = descriptorMap;
+    }
+
+
+    // Implementations for MemberInfoVisitor.
+
+    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+    {
+        collectName(programClassFile, programFieldInfo);
+    }
+
+
+    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+    {
+        collectName(programClassFile, programMethodInfo);
+    }
+
+
+    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+    {
+        collectName(libraryClassFile, libraryFieldInfo);
+    }
+
+
+    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+    {
+        collectName(libraryClassFile, libraryMethodInfo);
+    }
+
+
+    /**
+     * Inserts the new name of the given class member into the map.
+     * @param classFile  the class file of the given member.
+     * @param memberInfo the class member to be linked.
+     */
+    private void collectName(ClassFile classFile, MemberInfo memberInfo)
+    {
+        // Special cases: <clinit> and <init> are always kept unchanged.
+        // We can ignore them here.
+        String name = memberInfo.getName(classFile);
+        if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) ||
+            name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
+        {
+            return;
+        }
+
+        // Get the member's new name.
+        String newName = MemberInfoObfuscator.newMemberName(memberInfo);
+
+        // Remember it, if it has already been set.
+        if (newName != null)
+        {
+            // Get the member's descriptor.
+            String descriptor = memberInfo.getDescriptor(classFile);
+
+            // Check whether we're allowed to do aggressive overloading
+            if (!allowAggressiveOverloading)
+            {
+                // Trim the return argument from the descriptor if not.
+                // Works for fields and methods alike.
+                descriptor = descriptor.substring(0, descriptor.indexOf(')')+1);
+            }
+
+            // Put the [descriptor - new name] in the map,
+            // creating a new [new name - old name] map if necessary.
+            Map newNameMap = MemberInfoObfuscator.retrieveNameMap(descriptorMap, descriptor);
+
+            // Is the other original name different from this original name?
+            if (newNameMap.get(newName) == null ||
+                MemberInfoObfuscator.hasFixedNewMemberName(memberInfo))
+            {
+                // Remember not to use the new name again in this name space.
+                newNameMap.put(newName, name);
+            }
+        }
+    }
+}
diff --git a/src/proguard/classfile/visitor/MemberInfoNameFilter.java b/src/proguard/obfuscate/MemberInfoNameConflictFilter.java
similarity index 54%
copy from src/proguard/classfile/visitor/MemberInfoNameFilter.java
copy to src/proguard/obfuscate/MemberInfoNameConflictFilter.java
index 1da77ed..7a8ef62 100644
--- a/src/proguard/classfile/visitor/MemberInfoNameFilter.java
+++ b/src/proguard/obfuscate/MemberInfoNameConflictFilter.java
@@ -1,8 +1,8 @@
-/* $Id: MemberInfoNameFilter.java,v 1.9 2004/11/27 10:09:26 eric Exp $
+/* $Id: MemberInfoNameConflictFilter.java,v 1.3 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -18,37 +18,39 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-package proguard.classfile.visitor;
+package proguard.obfuscate;
 
 import proguard.classfile.*;
-import proguard.util.*;
+import proguard.classfile.visitor.MemberInfoVisitor;
 
+import java.util.*;
 
 /**
  * This <code>MemberInfoVisitor</code> delegates its visits to another given
- * <code>MemberInfoVisitor</code>, but only when the visited member
- * has a name that matches a given regular expression.
+ * <code>MemberInfoVisitor</code>, but only when the visited member has been
+ * marked as having a conflicting name.
+ *
+ * @see MemberInfoLinker
+ * @see MemberInfoObfuscator
  *
  * @author Eric Lafortune
  */
-public class MemberInfoNameFilter implements MemberInfoVisitor
+public class MemberInfoNameConflictFilter implements MemberInfoVisitor
 {
-    private StringMatcher     regularExpressionMatcher;
+    private static final String CONFLICT = "_ CONFLICT _";
+
+
     private MemberInfoVisitor memberInfoVisitor;
 
 
     /**
-     * Creates a new MemberInfoNameFilter.
-     * @param regularExpression the regular expression against which class names
-     *                          will be matched.
-     * @param memberInfoVisitor the <code>MemberInfoVisitor</code> to which visits
-     *                          will be delegated.
+     * Creates a new MemberInfoNameConflictFilter.
+     * @param memberInfoVisitor the <code>MemberInfoVisitor</code> to which
+     *                          visits will be delegated.
      */
-    public MemberInfoNameFilter(String            regularExpression,
-                                MemberInfoVisitor memberInfoVisitor)
+    public MemberInfoNameConflictFilter(MemberInfoVisitor memberInfoVisitor)
     {
-        this.regularExpressionMatcher = new ClassNameMatcher(regularExpression);
-        this.memberInfoVisitor        = memberInfoVisitor;
+        this.memberInfoVisitor = memberInfoVisitor;
     }
 
 
@@ -56,7 +58,7 @@ public class MemberInfoNameFilter implements MemberInfoVisitor
 
     public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
     {
-        if (accepted(programFieldInfo.getName(programClassFile)))
+        if (hasConflictingName(programFieldInfo))
         {
             memberInfoVisitor.visitProgramFieldInfo(programClassFile, programFieldInfo);
         }
@@ -65,35 +67,39 @@ public class MemberInfoNameFilter implements MemberInfoVisitor
 
     public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
-        if (accepted(programMethodInfo.getName(programClassFile)))
+        if (hasConflictingName(programMethodInfo))
         {
             memberInfoVisitor.visitProgramMethodInfo(programClassFile, programMethodInfo);
         }
     }
 
 
-    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
-    {
-        if (accepted(libraryFieldInfo.getName(libraryClassFile)))
-        {
-            memberInfoVisitor.visitLibraryFieldInfo(libraryClassFile, libraryFieldInfo);
-        }
-    }
+    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
 
 
-    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+    // Small utility methods.
+
+    /**
+     * Marks the given class member as having a conflicting name.
+     * @param memberInfo the class member.
+     */
+    static void markConflictingName(MemberInfo memberInfo)
     {
-        if (accepted(libraryMethodInfo.getName(libraryClassFile)))
-        {
-            memberInfoVisitor.visitLibraryMethodInfo(libraryClassFile, libraryMethodInfo);
-        }
+        MemberInfoObfuscator.setNewMemberName(memberInfo, CONFLICT);
     }
 
 
-    // Small utility methods.
-
-    private boolean accepted(String name)
+    /**
+     * Returns whether the given class member has been marked as having a
+     * conflicting name.
+     * @param memberInfo the class member.
+     */
+    static boolean hasConflictingName(MemberInfo memberInfo)
     {
-        return regularExpressionMatcher.matches(name);
+        String newName = MemberInfoObfuscator.newMemberName(memberInfo);
+
+        return newName != null &&
+               newName.equals(CONFLICT);
     }
 }
diff --git a/src/proguard/obfuscate/MemberInfoObfuscator.java b/src/proguard/obfuscate/MemberInfoObfuscator.java
index 94d3171..a693363 100644
--- a/src/proguard/obfuscate/MemberInfoObfuscator.java
+++ b/src/proguard/obfuscate/MemberInfoObfuscator.java
@@ -1,8 +1,8 @@
-/* $Id: MemberInfoObfuscator.java,v 1.12 2004/12/11 16:35:23 eric Exp $
+/* $Id: MemberInfoObfuscator.java,v 1.14 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -21,335 +21,132 @@
 package proguard.obfuscate;
 
 import proguard.classfile.*;
-import proguard.classfile.visitor.*;
+import proguard.classfile.util.MethodInfoLinker;
+import proguard.classfile.visitor.MemberInfoVisitor;
 
-import java.io.IOException;
 import java.util.*;
 
-
 /**
- * This ClassFileVisitor obfuscates all class members in the name spaces of all
- * visited class file. The class members must have been linked before applying this
- * visitor. The class file is typically a class file that is not being subclassed.
+ * This MemberInfoVisitor obfuscates all class members that it visits.
+ * It uses names from the given name factory. At the same time, it avoids names
+ * from the given descriptor map.
+ * The class members must have been linked before applying this visitor.
  *
- * @see MemberInfoLinker
+ * @see MethodInfoLinker
  *
  * @author Eric Lafortune
  */
-public class MemberInfoObfuscator implements ClassFileVisitor
+public class MemberInfoObfuscator implements MemberInfoVisitor
 {
-    private static final char UNIQUE_SUFFIX = '_';
-
-    private boolean allowAggressiveOverloading;
-
-    private NameFactory nameFactory       = new SimpleNameFactory();
-    private NameFactory uniqueNameFactory = new SimpleNameFactory();
-
-    // Some objects that are reset and reused every time.
-
-    // The main maps: [class member descriptor - new name - name]
-    private final Map nonPrivateDescriptorMap = new HashMap();
-    private final Map privateDescriptorMap    = new HashMap();
-
+    private boolean     allowAggressiveOverloading;
+    private NameFactory nameFactory;
+    private Map         descriptorMap;
 
 
     /**
-     * Creates a new MemberObfuscator.
+     * Creates a new MemberInfoObfuscator.
      * @param allowAggressiveOverloading a flag that specifies whether class
      *                                   members can be overloaded aggressively.
-     * @param obfuscationDictionary      the optional name of a file from which
-     *                                   obfuscated method names can be read.
+     * @param nameFactory                the factory that can produce
+     *                                   obfuscated member names.
+     * @param descriptorMap              the map of names to avoid:
+     *                                   [member descriptor - new name - old name].
      */
-    public MemberInfoObfuscator(boolean allowAggressiveOverloading,
-                                String  obfuscationDictionary)
-    throws IOException
+    public MemberInfoObfuscator(boolean     allowAggressiveOverloading,
+                                NameFactory nameFactory,
+                                Map         descriptorMap)
     {
         this.allowAggressiveOverloading = allowAggressiveOverloading;
-
-        // Get names from the obfuscation dictionary, if specified.
-        if (obfuscationDictionary != null)
-        {
-            nameFactory = new ReadNameFactory(obfuscationDictionary, nameFactory);
-        }
+        this.nameFactory                = nameFactory;
+        this.descriptorMap              = descriptorMap;
     }
 
 
-    // Implementations for ClassFileVisitor.
 
-    public void visitProgramClassFile(ProgramClassFile programClassFile)
-    {
-        // Collect all preset new member names in this class's name space.
-        // This actually includes preset new private member names.
-        programClassFile.hierarchyAccept(true, true, true, false,
-                                         new AllMemberInfoVisitor(
-                                         new MyNewNameCollector(nonPrivateDescriptorMap)));
-
-        // Assign new names to all non-private members in this class's name space.
-        programClassFile.hierarchyAccept(true, true, true, false,
-                                         new MyNonPrivateMemberInfoObfuscator());
-
-        // Assign new names to all private members in this class's name space.
-        programClassFile.hierarchyAccept(true, true, true, false,
-                                         new MyPrivateMemberInfoObfuscator());
-
-        // Clean up for obfuscation of the next name space.
-        nonPrivateDescriptorMap.clear();
-    }
 
+    // Implementations for MemberInfoVisitor.
 
-    public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
     {
+        visitMemberInfo(programClassFile, programFieldInfo);
     }
 
 
-    private class MyNonPrivateMemberInfoObfuscator implements ClassFileVisitor
+    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
-        // Implementations for ClassFileVisitor.
-
-        public void visitProgramClassFile(ProgramClassFile programClassFile)
+        // Special cases: <clinit> and <init> are always kept unchanged.
+        // We can ignore them here.
+        String name = programMethodInfo.getName(programClassFile);
+        if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) ||
+            name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
         {
-            MemberInfoAccessFilter nonPrivateNewNameAssigner =
-                new MemberInfoAccessFilter(
-                0,
-                ClassConstants.INTERNAL_ACC_PRIVATE,
-                new MyNewNameAssigner(nonPrivateDescriptorMap));
-
-            programClassFile.fieldsAccept(nonPrivateNewNameAssigner);
-            programClassFile.methodsAccept(nonPrivateNewNameAssigner);
+            return;
         }
 
-
-        public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
-        {
-        }
+        visitMemberInfo(programClassFile, programMethodInfo);
     }
 
 
-    private class MyPrivateMemberInfoObfuscator implements ClassFileVisitor
-    {
-        // Implementations for ClassFileVisitor.
-
-        public void visitProgramClassFile(ProgramClassFile programClassFile)
-        {
-            MemberInfoAccessFilter privateNewNameAssigner =
-                new MemberInfoAccessFilter(
-                ClassConstants.INTERNAL_ACC_PRIVATE,
-                0,
-                new MyNewNameAssigner(privateDescriptorMap, nonPrivateDescriptorMap));
-
-            programClassFile.fieldsAccept(privateNewNameAssigner);
-            programClassFile.methodsAccept(privateNewNameAssigner);
-
-            // Clean up for obfuscation of the next class.
-            privateDescriptorMap.clear();
-        }
+    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
 
 
-        public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
-        {
-        }
-    }
-
-
-    private class MyNewNameCollector implements MemberInfoVisitor
+    /**
+     * Inserts the given class member into the main map.
+     * @param classFile  the class file of the given member.
+     * @param memberInfo the class member to be linked.
+     */
+    private void visitMemberInfo(ClassFile classFile, MemberInfo memberInfo)
     {
-        private final Map descriptorMap;
-
+        // Get the member's name and descriptor.
+        String name       = memberInfo.getName(classFile);
+        String descriptor = memberInfo.getDescriptor(classFile);
 
-        public MyNewNameCollector(Map descriptorMap)
+        // Check whether we're allowed to do aggressive overloading
+        if (!allowAggressiveOverloading)
         {
-            this.descriptorMap = descriptorMap;
+            // Trim the return argument from the descriptor if not.
+            // Works for fields and methods alike.
+            descriptor = descriptor.substring(0, descriptor.indexOf(')')+1);
         }
 
+        // Put the [descriptor - new name] in the map,
+        // creating a new [new name - old name] map if necessary.
+        Map newNameMap = retrieveNameMap(descriptorMap, descriptor);
 
-        // Implementations for MemberInfoVisitor.
+        // Get the member's new name.
+        String newName = newMemberName(memberInfo);
 
-        public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+        // Assign a new one, if necessary.
+        if (newName == null)
         {
-            visitMemberInfo(programClassFile, programFieldInfo);
-        }
+            // Find an acceptable new name.
+            nameFactory.reset();
 
-
-        public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
-        {
-            visitMemberInfo(programClassFile, programMethodInfo);
-        }
-
-
-        public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
-        {
-            // Make sure the library field keeps its name.
-            String name = libraryFieldInfo.getName(libraryClassFile);
-            setNewMemberName(libraryFieldInfo, name);
-
-            visitMemberInfo(libraryClassFile, libraryFieldInfo);
-        }
-
-
-        public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
-        {
-            // Make sure the library method keeps its name.
-            String name = libraryMethodInfo.getName(libraryClassFile);
-            setNewMemberName(libraryMethodInfo, name);
-
-            visitMemberInfo(libraryClassFile, libraryMethodInfo);
-        }
-
-
-        /**
-         * Inserts the new name of the given class member into the main map.
-         * @param classFile  the class file of the given member.
-         * @param memberInfo the class member to be linked.
-         */
-        private void visitMemberInfo(ClassFile classFile, MemberInfo memberInfo)
-        {
-            // Special cases: <clinit> and <init> are always kept unchanged.
-            // We can ignore them here.
-            String name = memberInfo.getName(classFile);
-            if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) ||
-                name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
+            do
             {
-                return;
+                newName = nameFactory.nextName();
             }
+            while (newNameMap.containsKey(newName));
 
-            // Get the member's new name.
-            String newName = newMemberName(memberInfo);
+            // Assign the new name.
+            setNewMemberName(memberInfo, newName);
 
-            // Remember it, if it was set.
-            if (newName != null)
-            {
-                // Get the member's descriptor.
-                String descriptor = memberInfo.getDescriptor(classFile);
-
-                // Check whether we're allowed to do aggressive overloading
-                if (!allowAggressiveOverloading)
-                {
-                    // Trim the return argument from the descriptor if not.
-                    // Works for fields and methods alike.
-                    descriptor = descriptor.substring(0, descriptor.indexOf(')')+1);
-                }
-
-                // Put the [descriptor - new name] in the map,
-                // creating a new set of new names if necessary.
-                Map newNameMap = retrieveNameMap(descriptorMap, descriptor);
-
-                // Is the other original name different from this original
-                // name?
-                String otherName = (String)newNameMap.get(newName);
-                if (otherName != null &&
-                    !otherName.equals(name))
-                {
-                    // There's a conflict! A member (with a given old name) in a
-                    // first namespace has received the same new name as this
-                    // member (with a different old name) in a second name space,
-                    // and now these two have to live together in this name space.
-                    // Assign a truly unique new name to this member.
-                    setNewMemberName(memberInfo, uniqueNameFactory.nextName() + UNIQUE_SUFFIX);
-                }
-                else
-                {
-                    // Remember not to use the new name again in this name space.
-                    newNameMap.put(newName, name);
-                }
-            }
+            // Remember not to use the new name again in this name space.
+            newNameMap.put(newName, name);
         }
-    }
-
-
-    private class MyNewNameAssigner implements MemberInfoVisitor
-    {
-        private final Map descriptorMap;
-        private final Map secondaryDescriptorMap;
-
-
-        public MyNewNameAssigner(Map descriptorMap)
+        else if (!name.equals(newNameMap.get(newName)))
         {
-            this(descriptorMap, null);
-        }
+            // TODO: Preferentially keep the library method's name.
+            // TODO: Detect conflicting library member names.
 
+            // There's a conflict! A member (with a given old name) in a
+            // first namespace has received the same new name as this
+            // member (with a different old name) in a second name space,
+            // and now these two have to live together in this name space.
 
-        public MyNewNameAssigner(Map descriptorMap,
-                                 Map secondaryDescriptorMap)
-        {
-            this.descriptorMap          = descriptorMap;
-            this.secondaryDescriptorMap = secondaryDescriptorMap;
-        }
-
-
-        // Implementations for MemberInfoVisitor.
-
-        public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
-        {
-            visitMemberInfo(programClassFile, programFieldInfo);
-        }
-
-
-        public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
-        {
-            visitMemberInfo(programClassFile, programMethodInfo);
-        }
-
-
-        public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
-        public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
-
-
-        /**
-         * Inserts the given class member into the main map.
-         * @param classFile  the class file of the given member.
-         * @param memberInfo the class member to be linked.
-         */
-        private void visitMemberInfo(ClassFile classFile, MemberInfo memberInfo)
-        {
-            // Special cases: <clinit> and <init> are always kept unchanged.
-            // We can ignore them here.
-            String name = memberInfo.getName(classFile);
-            if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) ||
-                name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
-            {
-                return;
-            }
-
-            // Get the member's new name.
-            String newName = newMemberName(memberInfo);
-
-            // Assign a new one, if necessary.
-            if (newName == null)
-            {
-                // Get the member's descriptor.
-                String descriptor = memberInfo.getDescriptor(classFile);
-
-                // Check whether we're allowed to do aggressive overloading
-                if (!allowAggressiveOverloading)
-                {
-                    // Trim the return argument from the descriptor if not.
-                    // Works for fields and methods alike.
-                    descriptor = descriptor.substring(0, descriptor.indexOf(')')+1);
-                }
-
-                // Retrieve the new [ new name - old name ] map for the given
-                // descriptor, creating a new one if necessary.
-                Map newNameMap          = retrieveNameMap(descriptorMap, descriptor);
-                Map secondaryNewNameMap = secondaryDescriptorMap == null ? null :
-                    (Map)secondaryDescriptorMap.get(descriptor);
-
-                // Find a unique new name.
-                nameFactory.reset();
-
-                do
-                {
-                    newName = nameFactory.nextName();
-                }
-                while (newNameMap.containsKey(newName) ||
-                       (secondaryNewNameMap != null &&
-                        secondaryNewNameMap.containsKey(newName)));
-
-                // Assign the new name.
-                setNewMemberName(memberInfo, newName);
-
-                // Remember not to use the new name again in this name space.
-                newNameMap.put(newName, name);
-            }
+            // Mark the name as conflicting.
+            MemberInfoNameConflictFilter.markConflictingName(memberInfo);
         }
     }
 
@@ -357,14 +154,14 @@ public class MemberInfoObfuscator implements ClassFileVisitor
     // Small utility methods.
 
     /**
-     * Gets the nested set of new names, based on the given map
-     * [descriptor - nested set of new names] and a given descriptor.
-     * A new empty set is created if necessary.
-     * @param descriptorMap the map of descriptors to [ new name - member info ] maps.
+     * Gets the [new name - old name] map, based on the given map
+     * [descriptor - new name - old name] and a given descriptor.
+     * A new empty map is created if necessary.
+     * @param descriptorMap the map of descriptors to [new name - old name] maps.
      * @param descriptor    the class member descriptor.
-     * @return the nested set of new names.
+     * @return the corresponding [new name - old name] map.
      */
-    private Map retrieveNameMap(Map descriptorMap, String descriptor)
+    static Map retrieveNameMap(Map descriptorMap, String descriptor)
     {
         // See if we can find the nested map with this descriptor key.
         Map nameMap = (Map)descriptorMap.get(descriptor);
@@ -381,13 +178,48 @@ public class MemberInfoObfuscator implements ClassFileVisitor
 
 
     /**
+     * Assigns a fixed new name to the given class member.
+     * @param memberInfo the class member.
+     * @param name       the new name.
+     */
+    static void setFixedNewMemberName(MemberInfo memberInfo, String name)
+    {
+        VisitorAccepter lastVisitorAccepter = MethodInfoLinker.lastVisitorAccepter(memberInfo);
+
+        if (!(lastVisitorAccepter instanceof LibraryMemberInfo) &&
+            !(lastVisitorAccepter instanceof MyFixedName))
+        {
+            lastVisitorAccepter.setVisitorInfo(new MyFixedName(name));
+        }
+        else
+        {
+            lastVisitorAccepter.setVisitorInfo(name);
+        }
+    }
+
+
+    /**
      * Assigns a new name to the given class member.
-     * @param memberInfo the given class member.
+     * @param memberInfo the class member.
      * @param name       the new name.
      */
     static void setNewMemberName(MemberInfo memberInfo, String name)
     {
-        MemberInfoLinker.lastMemberInfo(memberInfo).setVisitorInfo(name);
+        MethodInfoLinker.lastVisitorAccepter(memberInfo).setVisitorInfo(name);
+    }
+
+
+    /**
+     * Returns whether the new name of the given class member is fixed.
+     * @param memberInfo the given class member.
+     * @return whether its new name is fixed.
+     */
+    static boolean hasFixedNewMemberName(MemberInfo memberInfo)
+    {
+        VisitorAccepter lastVisitorAccepter = MethodInfoLinker.lastVisitorAccepter(memberInfo);
+
+        return lastVisitorAccepter instanceof LibraryMemberInfo ||
+               lastVisitorAccepter instanceof MyFixedName;
     }
 
 
@@ -399,6 +231,36 @@ public class MemberInfoObfuscator implements ClassFileVisitor
      */
     static String newMemberName(MemberInfo memberInfo)
     {
-        return (String)MemberInfoLinker.lastMemberInfo(memberInfo).getVisitorInfo();
+        return (String)MethodInfoLinker.lastVisitorAccepter(memberInfo).getVisitorInfo();
+    }
+
+
+    /**
+     * This VisitorAccepter can be used to wrap a name string, to indicate that
+     * the name is fixed.
+     */
+    private static class MyFixedName implements VisitorAccepter
+    {
+        private String newName;
+
+
+        public MyFixedName(String newName)
+        {
+            this.newName = newName;
+        }
+
+
+        // Implementations for VisitorAccepter.
+
+        public Object getVisitorInfo()
+        {
+            return newName;
+        }
+
+
+        public void setVisitorInfo(Object visitorInfo)
+        {
+            newName = (String)visitorInfo;
+        }
     }
 }
diff --git a/src/proguard/classfile/visitor/MemberInfoNameFilter.java b/src/proguard/obfuscate/MemberInfoSpecialNameFilter.java
similarity index 63%
copy from src/proguard/classfile/visitor/MemberInfoNameFilter.java
copy to src/proguard/obfuscate/MemberInfoSpecialNameFilter.java
index 1da77ed..e7c18ca 100644
--- a/src/proguard/classfile/visitor/MemberInfoNameFilter.java
+++ b/src/proguard/obfuscate/MemberInfoSpecialNameFilter.java
@@ -1,8 +1,8 @@
-/* $Id: MemberInfoNameFilter.java,v 1.9 2004/11/27 10:09:26 eric Exp $
+/* $Id: MemberInfoSpecialNameFilter.java,v 1.3 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -18,37 +18,37 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-package proguard.classfile.visitor;
+package proguard.obfuscate;
 
 import proguard.classfile.*;
-import proguard.util.*;
+import proguard.classfile.visitor.MemberInfoVisitor;
 
+import java.util.*;
 
 /**
  * This <code>MemberInfoVisitor</code> delegates its visits to another given
- * <code>MemberInfoVisitor</code>, but only when the visited member
- * has a name that matches a given regular expression.
+ * <code>MemberInfoVisitor</code>, but only when the visited member has a
+ * special new name. A special name is a name that might have been produced by
+ * a <code>SpecialNameFactory</code>.
+ *
+ * @see MemberInfoObfuscator
+ * @see SpecialNameFactory
  *
  * @author Eric Lafortune
  */
-public class MemberInfoNameFilter implements MemberInfoVisitor
+public class MemberInfoSpecialNameFilter implements MemberInfoVisitor
 {
-    private StringMatcher     regularExpressionMatcher;
     private MemberInfoVisitor memberInfoVisitor;
 
 
     /**
-     * Creates a new MemberInfoNameFilter.
-     * @param regularExpression the regular expression against which class names
-     *                          will be matched.
-     * @param memberInfoVisitor the <code>MemberInfoVisitor</code> to which visits
-     *                          will be delegated.
+     * Creates a new MemberInfoSpecialNameFilter.
+     * @param memberInfoVisitor the <code>MemberInfoVisitor</code> to which
+     *                          visits will be delegated.
      */
-    public MemberInfoNameFilter(String            regularExpression,
-                                MemberInfoVisitor memberInfoVisitor)
+    public MemberInfoSpecialNameFilter(MemberInfoVisitor memberInfoVisitor)
     {
-        this.regularExpressionMatcher = new ClassNameMatcher(regularExpression);
-        this.memberInfoVisitor        = memberInfoVisitor;
+        this.memberInfoVisitor = memberInfoVisitor;
     }
 
 
@@ -56,7 +56,7 @@ public class MemberInfoNameFilter implements MemberInfoVisitor
 
     public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
     {
-        if (accepted(programFieldInfo.getName(programClassFile)))
+        if (isSpecialName(programFieldInfo))
         {
             memberInfoVisitor.visitProgramFieldInfo(programClassFile, programFieldInfo);
         }
@@ -65,7 +65,7 @@ public class MemberInfoNameFilter implements MemberInfoVisitor
 
     public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
-        if (accepted(programMethodInfo.getName(programClassFile)))
+        if (isSpecialName(programMethodInfo))
         {
             memberInfoVisitor.visitProgramMethodInfo(programClassFile, programMethodInfo);
         }
@@ -74,7 +74,7 @@ public class MemberInfoNameFilter implements MemberInfoVisitor
 
     public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
     {
-        if (accepted(libraryFieldInfo.getName(libraryClassFile)))
+        if (isSpecialName(libraryFieldInfo))
         {
             memberInfoVisitor.visitLibraryFieldInfo(libraryClassFile, libraryFieldInfo);
         }
@@ -83,7 +83,7 @@ public class MemberInfoNameFilter implements MemberInfoVisitor
 
     public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
     {
-        if (accepted(libraryMethodInfo.getName(libraryClassFile)))
+        if (isSpecialName(libraryMethodInfo))
         {
             memberInfoVisitor.visitLibraryMethodInfo(libraryClassFile, libraryMethodInfo);
         }
@@ -92,8 +92,12 @@ public class MemberInfoNameFilter implements MemberInfoVisitor
 
     // Small utility methods.
 
-    private boolean accepted(String name)
+    /**
+     * Returns whether the given class member has a special new name.
+     * @param memberInfo the class member.
+     */
+    private static boolean isSpecialName(MemberInfo memberInfo)
     {
-        return regularExpressionMatcher.matches(name);
+        return SpecialNameFactory.isSpecialName(MemberInfoObfuscator.newMemberName(memberInfo));
     }
 }
diff --git a/src/proguard/obfuscate/MultiMappingProcessor.java b/src/proguard/obfuscate/MultiMappingProcessor.java
index 14de028..7f0c36d 100644
--- a/src/proguard/obfuscate/MultiMappingProcessor.java
+++ b/src/proguard/obfuscate/MultiMappingProcessor.java
@@ -1,8 +1,8 @@
-/* $Id: MultiMappingProcessor.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: MultiMappingProcessor.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/obfuscate/NameAndTypeShrinker.java b/src/proguard/obfuscate/NameAndTypeShrinker.java
index ceccded..299f51d 100644
--- a/src/proguard/obfuscate/NameAndTypeShrinker.java
+++ b/src/proguard/obfuscate/NameAndTypeShrinker.java
@@ -1,8 +1,8 @@
-/* $Id: NameAndTypeShrinker.java,v 1.23 2004/11/20 15:41:24 eric Exp $
+/* $Id: NameAndTypeShrinker.java,v 1.24 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/obfuscate/NameAndTypeUsageMarker.java b/src/proguard/obfuscate/NameAndTypeUsageMarker.java
index 578a9f0..1d29836 100644
--- a/src/proguard/obfuscate/NameAndTypeUsageMarker.java
+++ b/src/proguard/obfuscate/NameAndTypeUsageMarker.java
@@ -1,8 +1,8 @@
-/* $Id: NameAndTypeUsageMarker.java,v 1.13 2004/11/26 12:46:43 eric Exp $
+/* $Id: NameAndTypeUsageMarker.java,v 1.14 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/obfuscate/NameFactory.java b/src/proguard/obfuscate/NameFactory.java
index 0d06c5d..1fc0d4d 100644
--- a/src/proguard/obfuscate/NameFactory.java
+++ b/src/proguard/obfuscate/NameFactory.java
@@ -1,8 +1,8 @@
-/* $Id: NameFactory.java,v 1.13 2004/11/01 21:17:51 eric Exp $
+/* $Id: NameFactory.java,v 1.14 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/visitor/AllFieldVisitor.java b/src/proguard/obfuscate/NameFactoryResetter.java
similarity index 62%
copy from src/proguard/classfile/visitor/AllFieldVisitor.java
copy to src/proguard/obfuscate/NameFactoryResetter.java
index ac23349..0fa5ba0 100644
--- a/src/proguard/classfile/visitor/AllFieldVisitor.java
+++ b/src/proguard/obfuscate/NameFactoryResetter.java
@@ -1,8 +1,8 @@
-/* $Id: AllFieldVisitor.java,v 1.12 2004/08/15 12:39:30 eric Exp $
+/* $Id: NameFactoryResetter.java,v 1.3 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -18,25 +18,31 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-package proguard.classfile.visitor;
+package proguard.obfuscate;
 
 import proguard.classfile.*;
+import proguard.classfile.visitor.ClassFileVisitor;
 
+import java.util.Map;
 
 /**
- * This ClassFileVisitor lets a given MemberInfoVisitor visit all FieldMemberInfo
- * objects of the class files it visits.
+ * This ClassFileVisitor resets a given name factory whenever it visits a class
+ * file.
  *
  * @author Eric Lafortune
  */
-public class AllFieldVisitor implements ClassFileVisitor
+public class NameFactoryResetter implements ClassFileVisitor
 {
-    private MemberInfoVisitor memberInfoVisitor;
+    private NameFactory nameFactory;
 
 
-    public AllFieldVisitor(MemberInfoVisitor memberInfoVisitor)
+    /**
+     * Creates a new MapCleaner.
+     * @param map the map to be cleared.
+     */
+    public NameFactoryResetter(NameFactory nameFactory)
     {
-        this.memberInfoVisitor = memberInfoVisitor;
+        this.nameFactory = nameFactory;
     }
 
 
@@ -44,12 +50,12 @@ public class AllFieldVisitor implements ClassFileVisitor
 
     public void visitProgramClassFile(ProgramClassFile programClassFile)
     {
-        programClassFile.fieldsAccept(memberInfoVisitor);
+        nameFactory.reset();
     }
 
 
     public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
     {
-        libraryClassFile.fieldsAccept(memberInfoVisitor);
+        nameFactory.reset();
     }
 }
diff --git a/src/proguard/obfuscate/NameMarker.java b/src/proguard/obfuscate/NameMarker.java
index ea359e9..0059dba 100644
--- a/src/proguard/obfuscate/NameMarker.java
+++ b/src/proguard/obfuscate/NameMarker.java
@@ -1,8 +1,8 @@
-/* $Id: NameMarker.java,v 1.14 2004/08/15 12:39:30 eric Exp $
+/* $Id: NameMarker.java,v 1.16 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -42,37 +42,76 @@ public class NameMarker
 
     public void visitProgramClassFile(ProgramClassFile programClassFile)
     {
-        // Make sure the class name will be kept.
-        ClassFileObfuscator.setNewClassName(programClassFile,
-                                            programClassFile.getName());
+        keepClassName(programClassFile);
     }
 
 
-    public void visitLibraryClassFile(LibraryClassFile libraryClassFile) {}
+    public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+    {
+        keepClassName(libraryClassFile);
+    }
 
 
     // Implementations for MemberInfoVisitor.
 
     public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
     {
-        visitMemberInfo(programClassFile, programFieldInfo);
+        keepFieldName(programClassFile, programFieldInfo);
     }
 
 
     public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
-        visitMemberInfo(programClassFile, programMethodInfo);
+        keepMethodName(programClassFile, programMethodInfo);
+    }
+
+
+    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+    {
+        keepFieldName(libraryClassFile, libraryFieldInfo);
+    }
+
+
+    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+    {
+        keepMethodName(libraryClassFile, libraryMethodInfo);
     }
 
 
-    private void visitMemberInfo(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+    // Small utility method.
+
+    /**
+     * Ensures the name of the given class name will be kept.
+     */
+    public void keepClassName(ClassFile classFile)
     {
-        // Make sure the class member name will be kept.
-        MemberInfoObfuscator.setNewMemberName(programMemberInfo,
-                                              programMemberInfo.getName(programClassFile));
+        ClassFileObfuscator.setNewClassName(classFile,
+                                            classFile.getName());
     }
 
 
-    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
-    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+    /**
+     * Ensures the name of the given field name will be kept.
+     */
+    private void keepFieldName(ClassFile classFile, FieldInfo fieldInfo)
+    {
+        MemberInfoObfuscator.setFixedNewMemberName(fieldInfo,
+                                                   fieldInfo.getName(classFile));
+    }
+
+
+    /**
+     * Ensures the name of the given method name will be kept.
+     */
+    private void keepMethodName(ClassFile classFile, MethodInfo methodInfo)
+    {
+        String name = methodInfo.getName(classFile);
+
+        if (!name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) &&
+            !name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
+        {
+            MemberInfoObfuscator.setFixedNewMemberName(methodInfo,
+                                                       methodInfo.getName(classFile));
+        }
+    }
 }
diff --git a/src/proguard/obfuscate/SimpleNameFactory.java b/src/proguard/obfuscate/SimpleNameFactory.java
index aae8e05..bbfdb53 100644
--- a/src/proguard/obfuscate/SimpleNameFactory.java
+++ b/src/proguard/obfuscate/SimpleNameFactory.java
@@ -1,8 +1,8 @@
-/* $Id: SimpleNameFactory.java,v 1.2 2004/11/20 15:41:24 eric Exp $
+/* $Id: SimpleNameFactory.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/classfile/editor/CodeAttrInfoEditorResetter.java b/src/proguard/obfuscate/SourceFileRenamer.java
similarity index 64%
copy from src/proguard/classfile/editor/CodeAttrInfoEditorResetter.java
copy to src/proguard/obfuscate/SourceFileRenamer.java
index 6e0b678..619a196 100644
--- a/src/proguard/classfile/editor/CodeAttrInfoEditorResetter.java
+++ b/src/proguard/obfuscate/SourceFileRenamer.java
@@ -1,8 +1,8 @@
-/* $Id: CodeAttrInfoEditorResetter.java,v 1.3 2004/10/10 20:56:58 eric Exp $
+/* $Id: SourceFileRenamer.java,v 1.2 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -18,32 +18,53 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-package proguard.classfile.editor;
+package proguard.obfuscate;
 
 import proguard.classfile.*;
 import proguard.classfile.attribute.*;
 import proguard.classfile.attribute.annotation.*;
-import proguard.classfile.instruction.*;
-import proguard.classfile.visitor.*;
+import proguard.classfile.editor.ConstantPoolEditor;
+import proguard.classfile.visitor.ClassFileVisitor;
 
 /**
- * This AttrInfoVisitor resets it CodeAttrInfoEditor whenever it visits a
- * code attribute.
+ * This ClassFileVisitor changes the name stored in the source file attributes
+ * and source dir attributes of the class files that it visits, if the
+ * atributes are present.
  *
  * @author Eric Lafortune
  */
-public class CodeAttrInfoEditorResetter implements AttrInfoVisitor
+public class SourceFileRenamer
+implements   ClassFileVisitor,
+             AttrInfoVisitor
 {
-    private CodeAttrInfoEditor codeAttrInfoEditor;
+    private ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor();
+
+    private String newSourceFileAttribute;
 
 
     /**
-     * Creates a new CodeAttrInfoEditorResetter.
-     * @param codeAttrInfoEditor the code attribute editor that will be reset.
+     * Creates a new SourceFileRenamer.
+     * @param newSourceFileAttribute the new string to be put in the source file
+     *                               attributes.
      */
-    public CodeAttrInfoEditorResetter(CodeAttrInfoEditor codeAttrInfoEditor)
+    public SourceFileRenamer(String newSourceFileAttribute)
+    {
+        this.newSourceFileAttribute = newSourceFileAttribute;
+    }
+
+
+    // Implementations for ClassFileVisitor.
+
+    public void visitProgramClassFile(ProgramClassFile programClassFile)
+    {
+        // Only visit the class file attributes.
+        programClassFile.attributesAccept(this);
+    }
+
+
+    public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
     {
-        this.codeAttrInfoEditor = codeAttrInfoEditor;
+        // Library class files don't have attributes.
     }
 
 
@@ -54,11 +75,10 @@ public class CodeAttrInfoEditorResetter implements AttrInfoVisitor
     public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
     public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
     public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+    public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo) {}
     public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
     public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
     public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
-    public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
-    public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
     public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
     public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
     public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
@@ -69,8 +89,20 @@ public class CodeAttrInfoEditorResetter implements AttrInfoVisitor
     public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {}
 
 
-    public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
+    public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo)
+    {
+        // Fix the source file attribute.
+        sourceFileAttrInfo.u2sourceFileIndex =
+            constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
+                                             newSourceFileAttribute);
+    }
+
+
+    public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo)
     {
-        codeAttrInfoEditor.reset(codeAttrInfo.u4codeLength);
+        // Fix the source file attribute.
+        sourceDirAttrInfo.u2sourceDirIndex =
+            constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
+                                             newSourceFileAttribute);
     }
 }
diff --git a/src/proguard/obfuscate/SpecialNameFactory.java b/src/proguard/obfuscate/SpecialNameFactory.java
new file mode 100644
index 0000000..90a3ae3
--- /dev/null
+++ b/src/proguard/obfuscate/SpecialNameFactory.java
@@ -0,0 +1,86 @@
+/* $Id: SpecialNameFactory.java,v 1.3 2005/06/11 13:21:35 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.obfuscate;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * This <code>NameFactory</code> generates names that are special, by appending
+ * a suffix.
+ *
+ * @author Eric Lafortune
+ */
+public class SpecialNameFactory implements NameFactory
+{
+    private static final char SPECIAL_SUFFIX = '_';
+
+
+    private final NameFactory nameFactory;
+
+
+    /**
+     * Creates a new <code>SpecialNameFactory</code>.
+     * @param nameFactory the name factory from which original names will be
+     *                    retrieved.
+     */
+    public SpecialNameFactory(NameFactory nameFactory)
+    {
+        this.nameFactory = nameFactory;
+    }
+
+
+    // Implementations for NameFactory.
+
+    public void reset()
+    {
+        nameFactory.reset();
+    }
+
+
+    public String nextName()
+    {
+        return nameFactory.nextName() + SPECIAL_SUFFIX;
+    }
+
+
+    // Small utility methods.
+
+    /**
+     * Returns whether the given name is special.
+     */
+    static boolean isSpecialName(String name)
+    {
+        return name != null &&
+               name.charAt(name.length()-1) == SPECIAL_SUFFIX;
+    }
+
+
+    public static void main(String[] args)
+    {
+        SpecialNameFactory factory = new SpecialNameFactory(new SimpleNameFactory());
+
+        for (int counter = 0; counter < 50; counter++)
+        {
+            System.out.println("["+factory.nextName()+"]");
+        }
+    }
+}
diff --git a/src/proguard/obfuscate/Utf8Shrinker.java b/src/proguard/obfuscate/Utf8Shrinker.java
index e01bbce..72dff91 100644
--- a/src/proguard/obfuscate/Utf8Shrinker.java
+++ b/src/proguard/obfuscate/Utf8Shrinker.java
@@ -1,8 +1,8 @@
-/* $Id: Utf8Shrinker.java,v 1.26 2004/10/10 20:56:58 eric Exp $
+/* $Id: Utf8Shrinker.java,v 1.27 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/obfuscate/Utf8UsageMarker.java b/src/proguard/obfuscate/Utf8UsageMarker.java
index f34abf0..fbc7c39 100644
--- a/src/proguard/obfuscate/Utf8UsageMarker.java
+++ b/src/proguard/obfuscate/Utf8UsageMarker.java
@@ -1,8 +1,8 @@
-/* $Id: Utf8UsageMarker.java,v 1.22 2004/11/20 15:41:24 eric Exp $
+/* $Id: Utf8UsageMarker.java,v 1.23 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/ChangedCodePrinter.java b/src/proguard/optimize/ChangedCodePrinter.java
index ab6875a..013cb5f 100644
--- a/src/proguard/optimize/ChangedCodePrinter.java
+++ b/src/proguard/optimize/ChangedCodePrinter.java
@@ -1,8 +1,8 @@
-/* $Id: ChangedCodePrinter.java,v 1.6 2004/11/20 15:41:24 eric Exp $
+/* $Id: ChangedCodePrinter.java,v 1.7 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/KeepMarker.java b/src/proguard/optimize/KeepMarker.java
index 1f5a52e..e54b5e7 100644
--- a/src/proguard/optimize/KeepMarker.java
+++ b/src/proguard/optimize/KeepMarker.java
@@ -1,4 +1,4 @@
-/* $Id: KeepMarker.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+/* $Id: KeepMarker.java,v 1.6 2005/06/05 15:54:09 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
@@ -21,6 +21,7 @@
 package proguard.optimize;
 
 import proguard.classfile.*;
+import proguard.classfile.util.MethodInfoLinker;
 import proguard.classfile.visitor.*;
 
 
@@ -43,7 +44,6 @@ public class KeepMarker
 
     public void visitProgramClassFile(ProgramClassFile programClassFile)
     {
-        // Make sure the class will be kept.
         markAsKept(programClassFile);
     }
 
@@ -55,20 +55,13 @@ public class KeepMarker
 
     public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
     {
-        visitMemberInfo(programClassFile, programFieldInfo);
+        markAsKept(programFieldInfo);
     }
 
 
     public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
-        visitMemberInfo(programClassFile, programMethodInfo);
-    }
-
-
-    private void visitMemberInfo(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
-    {
-        // Make sure the class member will be kept.
-        markAsKept(programMemberInfo);
+        markAsKept(MethodInfoLinker.lastMethodInfo(programMethodInfo));
     }
 
 
@@ -86,7 +79,6 @@ public class KeepMarker
 
     public static boolean isKept(VisitorAccepter visitorAccepter)
     {
-        return visitorAccepter == null                          ||
-               visitorAccepter.getVisitorInfo() == KEPT;
+        return MethodInfoLinker.lastVisitorAccepter(visitorAccepter).getVisitorInfo() == KEPT;
     }
 }
diff --git a/src/proguard/optimize/MethodOptimizationInfo.java b/src/proguard/optimize/MethodOptimizationInfo.java
new file mode 100644
index 0000000..ecbe438
--- /dev/null
+++ b/src/proguard/optimize/MethodOptimizationInfo.java
@@ -0,0 +1,114 @@
+/* $Id: MethodOptimizationInfo.java,v 1.4 2005/06/11 13:13:16 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize;
+
+import proguard.classfile.*;
+import proguard.classfile.util.MethodInfoLinker;
+
+/**
+ * This class stores some optimization information that can be attached to
+ * a method.
+ *
+ * @author Eric Lafortune
+ */
+public class MethodOptimizationInfo
+{
+    private boolean hasNoSideEffects = false;
+    private boolean hasSideEffects   = false;
+    private boolean canBeMadePrivate = true;
+    private long    usedVariables    = 0;
+
+
+    public void setNoSideEffects()
+    {
+        hasNoSideEffects = true;
+    }
+
+
+    public boolean hasNoSideEffects()
+    {
+        return hasNoSideEffects;
+    }
+
+
+    public void setSideEffects()
+    {
+        hasSideEffects = true;
+    }
+
+
+    public boolean hasSideEffects()
+    {
+        return hasSideEffects;
+    }
+
+
+    public void setCanNotBeMadePrivate()
+    {
+        canBeMadePrivate = false;
+    }
+
+
+    public boolean canBeMadePrivate()
+    {
+        return canBeMadePrivate;
+    }
+
+
+    public void setUsedVariables(long usedVariables)
+    {
+        this.usedVariables = usedVariables;
+    }
+
+
+    public long getUsedVariables()
+    {
+        return usedVariables;
+    }
+
+
+    public void setVariableUsed(int variableIndex)
+    {
+        usedVariables |= 1 << variableIndex;
+    }
+
+
+    public boolean isVariableUsed(int variableIndex)
+    {
+        return variableIndex >= 64 || (usedVariables & (1 << variableIndex)) != 0;
+    }
+
+
+    public static void setMethodOptimizationInfo(MethodInfo methodInfo)
+    {
+        MethodInfoLinker.lastMethodInfo(methodInfo).setVisitorInfo(new MethodOptimizationInfo());
+    }
+
+
+    public static MethodOptimizationInfo getMethodOptimizationInfo(MethodInfo methodInfo)
+    {
+        Object visitorInfo = MethodInfoLinker.lastMethodInfo(methodInfo).getVisitorInfo();
+
+        return visitorInfo instanceof MethodOptimizationInfo ?
+            (MethodOptimizationInfo)visitorInfo :
+            null;
+    }
+}
diff --git a/src/proguard/classfile/attribute/AllAttrInfoVisitor.java b/src/proguard/optimize/MethodOptimizationInfoSetter.java
similarity index 59%
copy from src/proguard/classfile/attribute/AllAttrInfoVisitor.java
copy to src/proguard/optimize/MethodOptimizationInfoSetter.java
index ca8582e..6ca2d2f 100644
--- a/src/proguard/classfile/attribute/AllAttrInfoVisitor.java
+++ b/src/proguard/optimize/MethodOptimizationInfoSetter.java
@@ -1,8 +1,8 @@
-/* $Id: AllAttrInfoVisitor.java,v 1.1 2004/10/10 21:10:04 eric Exp $
+/* $Id: MethodOptimizationInfoSetter.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2003 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -18,51 +18,39 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-package proguard.classfile.attribute;
+package proguard.optimize;
 
 import proguard.classfile.*;
 import proguard.classfile.visitor.*;
 
-
 /**
- * This MemberInfoVisitor lets a given AttrInfoVisitor visit all AttrInfo
- * objects of the program class members it visits.
+ * This MemberInfoVisitor attaches a MethodOptimizationInfo instance to every
+ * method that is not being kept that it visits.
  *
  * @author Eric Lafortune
  */
-public class AllAttrInfoVisitor implements MemberInfoVisitor
+public class MethodOptimizationInfoSetter implements MemberInfoVisitor
 {
-    private AttrInfoVisitor attrInfoVisitor;
-
-
-    public AllAttrInfoVisitor(AttrInfoVisitor attrInfoVisitor)
-    {
-        this.attrInfoVisitor = attrInfoVisitor;
-    }
-
-
     // Implementations for MemberInfoVisitor.
 
-    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
-    {
-        programFieldInfo.attributesAccept(programClassFile, attrInfoVisitor);
-    }
-
+    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
 
     public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
-        programMethodInfo.attributesAccept(programClassFile, attrInfoVisitor);
+        if (!KeepMarker.isKept(programMethodInfo))
+        {
+            MethodOptimizationInfo.setMethodOptimizationInfo(programMethodInfo);
+        }
     }
 
 
-    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
-    {
-        // Library class file fields don't have attributes.
-    }
-
+    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
 
     public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
     {
-        // Library class file methods don't have attributes.
+        if (!KeepMarker.isKept(libraryMethodInfo))
+        {
+            MethodOptimizationInfo.setMethodOptimizationInfo(libraryMethodInfo);
+        }
     }
 }
diff --git a/src/proguard/optimize/NoSideEffectMethodMarker.java b/src/proguard/optimize/NoSideEffectMethodMarker.java
index 2b69044..c5870d4 100644
--- a/src/proguard/optimize/NoSideEffectMethodMarker.java
+++ b/src/proguard/optimize/NoSideEffectMethodMarker.java
@@ -1,8 +1,8 @@
-/* $Id: NoSideEffectMethodMarker.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: NoSideEffectMethodMarker.java,v 1.5 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -35,18 +35,13 @@ import proguard.classfile.visitor.*;
 public class NoSideEffectMethodMarker
   implements MemberInfoVisitor
 {
-    // A visitor info flag to indicate that a MethodInfo object doesn't have
-    // anyside effects.
-    private static final Object NO_SIDE_EFFECTS = new Object();
-
-
     // Implementations for MemberInfoVisitor.
 
     public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
 
     public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
-        markAsNoSideEffects(programMethodInfo);
+        markNoSideEffects(programMethodInfo);
     }
 
 
@@ -54,21 +49,26 @@ public class NoSideEffectMethodMarker
 
     public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
     {
-        markAsNoSideEffects(libraryMethodInfo);
+        markNoSideEffects(libraryMethodInfo);
     }
 
 
     // Small utility methods.
 
-    public static void markAsNoSideEffects(VisitorAccepter visitorAccepter)
+    public static void markNoSideEffects(MethodInfo methodInfo)
     {
-        visitorAccepter.setVisitorInfo(NO_SIDE_EFFECTS);
+        MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(methodInfo);
+        if (info != null)
+        {
+            info.setNoSideEffects();
+        }
     }
 
 
-    public static boolean hasNoSideEffects(VisitorAccepter visitorAccepter)
+    public static boolean hasNoSideEffects(MethodInfo methodInfo)
     {
-        return visitorAccepter != null &&
-               visitorAccepter.getVisitorInfo() == NO_SIDE_EFFECTS;
+        MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(methodInfo);
+        return info != null &&
+               info.hasNoSideEffects();
     }
 }
diff --git a/src/proguard/optimize/NonPrivateMethodMarker.java b/src/proguard/optimize/NonPrivateMethodMarker.java
new file mode 100644
index 0000000..f66511f
--- /dev/null
+++ b/src/proguard/optimize/NonPrivateMethodMarker.java
@@ -0,0 +1,141 @@
+/* $Id: NonPrivateMethodMarker.java,v 1.6 2005/06/11 13:21:35 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This ClassFileVisitor marks all methods that can not be made private in the
+ * classes that it visits, and in the classes to which they refer.
+ *
+ * @author Eric Lafortune
+ */
+public class NonPrivateMethodMarker
+  implements ClassFileVisitor,
+             CpInfoVisitor,
+             MemberInfoVisitor
+{
+    private MethodImplementationFilter filteredMethodMarker = new MethodImplementationFilter(this);
+
+
+    // Implementations for ClassFileVisitor.
+
+    public void visitProgramClassFile(ProgramClassFile programClassFile)
+    {
+        // Explicitly mark the <clinit> method.
+        programClassFile.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_CLINIT,
+                                      ClassConstants.INTERNAL_METHOD_TYPE_CLINIT,
+                                      this);
+
+        // Explicitly mark the parameterless <init> method.
+        programClassFile.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_INIT,
+                                      ClassConstants.INTERNAL_METHOD_TYPE_INIT,
+                                      this);
+
+        // Go over all referenced methods.
+        programClassFile.constantPoolEntriesAccept(this);
+
+        // Go over all methods that may have implementations.
+        programClassFile.methodsAccept(filteredMethodMarker);
+    }
+
+
+    public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+    {
+        // Go over all methods.
+        libraryClassFile.methodsAccept(this);
+    }
+
+
+    // Implementations for CpInfoVisitor.
+
+    public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+    public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+    public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+    public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+    public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+    public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+    public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
+    public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo) {}
+    public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+
+
+    public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
+    {
+        // Implementations of the referenced method can never be made private.
+        interfaceMethodrefCpInfo.referencedMemberInfoAccept(this);
+    }
+
+
+    public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+    {
+        ClassFile referencedClassFile = methodrefCpInfo.referencedClassFile;
+
+        // Is it refering to a method in another class file?
+        if (referencedClassFile != null &&
+            !referencedClassFile.equals(classFile))
+        {
+            // The referenced method can never be made private.
+            methodrefCpInfo.referencedMemberInfoAccept(this);
+        }
+    }
+
+
+    // Implementations for MemberInfoVisitor.
+
+    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
+
+
+    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+    {
+        markCanNotBeMadePrivate(programMethodInfo);
+    }
+
+
+    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+
+
+    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+    {
+        markCanNotBeMadePrivate(libraryMethodInfo);
+    }
+
+
+    // Small utility methods.
+
+    public static void markCanNotBeMadePrivate(MethodInfo methodInfo)
+    {
+        MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(methodInfo);
+        if (info != null)
+        {
+            info.setCanNotBeMadePrivate();
+        }
+    }
+
+
+    public static boolean canBeMadePrivate(MethodInfo methodInfo)
+    {
+        MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(methodInfo);
+        return info != null &&
+               info.canBeMadePrivate();
+    }
+}
diff --git a/src/proguard/optimize/ParameterShrinker.java b/src/proguard/optimize/ParameterShrinker.java
new file mode 100644
index 0000000..ca1f752
--- /dev/null
+++ b/src/proguard/optimize/ParameterShrinker.java
@@ -0,0 +1,322 @@
+/* $Id: ParameterShrinker.java,v 1.4 2005/06/25 22:04:04 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.editor.*;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.MemberInfoVisitor;
+
+/**
+ * This MemberInfoVisitor removes unused parameters from the descriptors and
+ * the code of the methods that it visits. It also makes methods static if the
+ * 'this' parameter is unused.
+ *
+ * @see ParameterUsageMarker
+ * @author Eric Lafortune
+ */
+public class ParameterShrinker
+  implements MemberInfoVisitor,
+             AttrInfoVisitor
+{
+    private static final boolean DEBUG = false;
+
+
+    private ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor();
+    private VariableEditor     variableEditor;
+
+    // A parameter for the parameter annotation visiting methods.
+    private MethodInfo methodInfo;
+
+
+    /**
+     * Creates a new ParameterShrinker.
+     * @param codeLength an estimate of the maximum length of all the code
+     *                   that will be edited.
+     * @param maxLocals  an estimate of the maximum length of all the local
+     *                   variable frames that will be edited.
+     */
+    public ParameterShrinker(int codeLength, int maxLocals)
+    {
+        variableEditor = new VariableEditor(codeLength, maxLocals);
+    }
+
+
+    // Implementations for MemberInfoVisitor.
+
+    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
+
+
+    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+    {
+        // Update the descriptor if it has any unused parameters.
+        String descriptor    = programMethodInfo.getDescriptor(programClassFile);
+        String newDescriptor = shrinkDescriptor(programClassFile, programMethodInfo);
+        if (!descriptor.equals(newDescriptor))
+        {
+            // Update the parameter annotations.
+            this.methodInfo = programMethodInfo;
+            programMethodInfo.attributesAccept(programClassFile, this);
+
+            // TODO: Avoid duplicate constructors.
+            String name    = programMethodInfo.getName(programClassFile);
+            String newName = name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) ?
+                                 ClassConstants.INTERNAL_METHOD_NAME_INIT :
+                                 name + '$' + Long.toHexString(Math.abs((descriptor).hashCode()));
+
+            if (DEBUG)
+            {
+                System.out.println("ParameterShrinker:");
+                System.out.println("  Class file        = "+programClassFile.getName());
+                System.out.println("  Method name       = "+name);
+                System.out.println("                   -> "+newName);
+                System.out.println("  Method descriptor = "+descriptor);
+                System.out.println("                   -> "+newDescriptor);
+            }
+
+            // Update the name, if necessary.
+            if (!newName.equals(name))
+            {
+                programMethodInfo.u2nameIndex =
+                constantPoolEditor.addUtf8CpInfo(programClassFile, newName);
+            }
+
+            // Clear the unused referenced class files.
+            shrinkReferencedClassFiles(programClassFile, programMethodInfo);
+
+            // Update the descriptor.
+            programMethodInfo.u2descriptorIndex =
+                constantPoolEditor.addUtf8CpInfo(programClassFile, newDescriptor);
+        }
+
+        // Delete unused variables from the local variable frame.
+        variableEditor.reset(64);
+
+        for (int variableIndex = 0; variableIndex < 64; variableIndex++)
+        {
+            if (!VariableUsageMarker.isVariableUsed(programMethodInfo, variableIndex))
+            {
+                // Delete the unused variable.
+                variableEditor.deleteVariable(variableIndex);
+            }
+        }
+
+        // Shift all remaining variables in the byte code.
+        programMethodInfo.attributesAccept(programClassFile, variableEditor);
+
+        // Is the method not static, and can it be made static?
+        int accessFlags = programMethodInfo.getAccessFlags();
+        if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) == 0 &&
+            !VariableUsageMarker.isVariableUsed(programMethodInfo, 0))
+        {
+            if (DEBUG)
+            {
+                System.out.println("ParameterShrinker:");
+                System.out.println("  Class file = "+programClassFile.getName());
+                System.out.println("  Method     = "+programMethodInfo.getName(programClassFile)+programMethodInfo.getDescriptor(programClassFile));
+                System.out.println("    -> static");
+            }
+
+            // Make the method static.
+            programMethodInfo.u2accessFlags =
+                (accessFlags & ~ClassConstants.INTERNAL_ACC_FINAL) |
+                ClassConstants.INTERNAL_ACC_STATIC;
+        }
+    }
+
+
+    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+
+
+    // Implementations for AttrInfoVisitor.
+
+    public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
+    public void visitInnerClassesAttrInfo(ClassFile classFile, InnerClassesAttrInfo innerClassesAttrInfo) {}
+    public void visitEnclosingMethodAttrInfo(ClassFile classFile, EnclosingMethodAttrInfo enclosingMethodAttrInfo) {}
+    public void visitConstantValueAttrInfo(ClassFile classFile, FieldInfo fieldInfo, ConstantValueAttrInfo constantValueAttrInfo) {}
+    public void visitExceptionsAttrInfo(ClassFile classFile, MethodInfo methodInfo, ExceptionsAttrInfo exceptionsAttrInfo) {}
+    public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo) {}
+    public void visitLineNumberTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LineNumberTableAttrInfo lineNumberTableAttrInfo) {}
+    public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo) {}
+    public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo) {}
+    public void visitSourceFileAttrInfo(ClassFile classFile, SourceFileAttrInfo sourceFileAttrInfo) {}
+    public void visitSourceDirAttrInfo(ClassFile classFile, SourceDirAttrInfo sourceDirAttrInfo) {}
+    public void visitDeprecatedAttrInfo(ClassFile classFile, DeprecatedAttrInfo deprecatedAttrInfo) {}
+    public void visitSyntheticAttrInfo(ClassFile classFile, SyntheticAttrInfo syntheticAttrInfo) {}
+    public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo) {}
+    public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo) {}
+    public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo) {}
+    public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo) {}
+
+
+    public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo)
+    {
+        // Update the parameter annotations.
+        shrinkParameterAnnotations(classFile, runtimeVisibleParameterAnnotationsAttrInfo);
+    }
+
+
+    public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo)
+    {
+        // Update the parameter annotations.
+        shrinkParameterAnnotations(classFile, runtimeInvisibleParameterAnnotationsAttrInfo);
+    }
+
+
+    // Small utility methods.
+
+    /**
+     * Shrinks the given parameter annotations.
+     */
+    private void shrinkParameterAnnotations(ClassFile                           classFile,
+                                            RuntimeParameterAnnotationsAttrInfo runtimeParameterAnnotationsAttrInfo)
+    {
+        Annotation[][] annotations = runtimeParameterAnnotationsAttrInfo.parameterAnnotations;
+
+        // All parameters of non-static methods are shifted by one in the local
+        // variable frame.
+        int parameterIndex =
+            (methodInfo.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ?
+                0 : 1;
+
+        int annotationIndex    = 0;
+        int newAnnotationIndex = 0;
+
+        // Go over the parameters.
+        String descriptor = methodInfo.getDescriptor(classFile);
+        InternalTypeEnumeration internalTypeEnumeration =
+            new InternalTypeEnumeration(descriptor);
+
+        while (internalTypeEnumeration.hasMoreTypes())
+        {
+            String type = internalTypeEnumeration.nextType();
+            if (ClassUtil.isInternalClassType(type))
+            {
+                if (VariableUsageMarker.isVariableUsed(methodInfo, parameterIndex))
+                {
+                    annotations[newAnnotationIndex++] = annotations[annotationIndex];
+                }
+
+                annotationIndex++;
+            }
+
+            parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1;
+        }
+
+        runtimeParameterAnnotationsAttrInfo.u2numberOfParameters = newAnnotationIndex;
+
+        // Clear the unused entries.
+        while (newAnnotationIndex < annotationIndex)
+        {
+            annotations[newAnnotationIndex++] = null;
+        }
+    }
+
+
+    /**
+     * Returns a shrunk descriptor of the given method.
+     */
+    public static String shrinkDescriptor(ProgramClassFile  classFile,
+                                          ProgramMethodInfo methodInfo)
+    {
+        // All parameters of non-static methods are shifted by one in the local
+        // variable frame.
+        int parameterIndex =
+            (methodInfo.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ?
+                0 : 1;
+
+        // Go over the parameters.
+        InternalTypeEnumeration internalTypeEnumeration =
+            new InternalTypeEnumeration(methodInfo.getDescriptor(classFile));
+
+        StringBuffer newDescriptorBuffer = new StringBuffer();
+        newDescriptorBuffer.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_OPEN);
+
+        while (internalTypeEnumeration.hasMoreTypes())
+        {
+            String type = internalTypeEnumeration.nextType();
+            if (VariableUsageMarker.isVariableUsed(methodInfo, parameterIndex))
+            {
+                newDescriptorBuffer.append(type);
+            }
+
+            parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1;
+        }
+
+        newDescriptorBuffer.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE);
+        newDescriptorBuffer.append(internalTypeEnumeration.returnType());
+
+        return newDescriptorBuffer.toString();
+    }
+
+
+    /**
+     * Shrinks the array of referenced class files of the given method.
+     */
+    private static void shrinkReferencedClassFiles(ProgramClassFile  classFile,
+                                                   ProgramMethodInfo methodInfo)
+    {
+        ClassFile[] referencedClassFiles = methodInfo.referencedClassFiles;
+
+        if (referencedClassFiles != null)
+        {
+            // All parameters of non-static methods are shifted by one in the local
+            // variable frame.
+            int parameterIndex =
+                (methodInfo.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ?
+                    0 : 1;
+    
+            int referencedClassFileIndex    = 0;
+            int newReferencedClassFileIndex = 0;
+    
+            // Go over the parameters.
+            String descriptor = methodInfo.getDescriptor(classFile);
+            InternalTypeEnumeration internalTypeEnumeration =
+                new InternalTypeEnumeration(descriptor);
+    
+            while (internalTypeEnumeration.hasMoreTypes())
+            {
+                String type = internalTypeEnumeration.nextType();
+                if (ClassUtil.isInternalClassType(type))
+                {
+                    if (VariableUsageMarker.isVariableUsed(methodInfo, parameterIndex))
+                    {
+                        referencedClassFiles[newReferencedClassFileIndex++] =
+                            referencedClassFiles[referencedClassFileIndex];
+                    }
+    
+                    referencedClassFileIndex++;
+                }
+    
+                parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1;
+            }
+    
+            // Clear the unused entries.
+            while (newReferencedClassFileIndex < referencedClassFileIndex)
+            {
+                referencedClassFiles[newReferencedClassFileIndex++] = null;
+            }
+        }
+    }
+}
diff --git a/src/proguard/optimize/ParameterUsageMarker.java b/src/proguard/optimize/ParameterUsageMarker.java
new file mode 100644
index 0000000..ee8a7b6
--- /dev/null
+++ b/src/proguard/optimize/ParameterUsageMarker.java
@@ -0,0 +1,138 @@
+/* $Id: ParameterUsageMarker.java,v 1.4 2005/06/11 13:13:16 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize;
+
+import proguard.classfile.*;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+
+/**
+ * This MemberInfoVisitor marks the used method parameters methods in the
+ * class hierarchies. The used variables must have been marked first. The
+ * 'this' parameters of methods that have a hierarchy are marked too.
+ *
+ * @see VariableUsageMarker
+ * @author Eric Lafortune
+ */
+public class ParameterUsageMarker
+implements   MemberInfoVisitor
+{
+    // Implementations for MemberInfoVisitor.
+
+    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
+
+
+    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+    {
+        // Is this a native method?
+        if ((programMethodInfo.getAccessFlags() & ClassConstants.INTERNAL_ACC_NATIVE) != 0)
+        {
+            // All parameters can be considered as being used.
+            long usedParameters = parameterMask(programClassFile, programMethodInfo);
+
+            // Is this a non-static method?
+            if ((programMethodInfo.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) == 0)
+            {
+                // The 'this' parameter can be considered as being used too.
+                usedParameters = 1L | (usedParameters << 1);
+            }
+
+            // Mark the parameters.
+            markUsedVariables(programMethodInfo, usedParameters);
+        }
+
+        // Can the method have other implementations?
+        if (programClassFile.mayHaveImplementations(programMethodInfo))
+        {
+            // All implementations must at least keep the 'this' parameter too.
+            long usedParameters = 1L;
+
+            // Mark the parameters.
+            markUsedVariables(programMethodInfo, usedParameters);
+        }
+        // Is it an <init> method?
+        else if (programMethodInfo.getName(programClassFile).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
+        {
+            // Instance initializers always require the 'this' parameter.
+            long usedParameters = 1L;
+
+            // Is there a name clash with some existing <init> method?
+            if (programClassFile.findMethod(ClassConstants.INTERNAL_METHOD_NAME_INIT,
+                                            ParameterShrinker.shrinkDescriptor(programClassFile,
+                                                                               programMethodInfo)) != null)
+            {
+                // The shrinking is off. Mark all parameters.
+                usedParameters |=  parameterMask(programClassFile, programMethodInfo) << 1;
+            }
+
+            // Mark the parameters.
+            markUsedVariables(programMethodInfo, usedParameters);
+        }
+    }
+
+
+    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+
+
+    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+    {
+        // Can the method have other implementations?
+        if (libraryClassFile.mayHaveImplementations(libraryMethodInfo))
+        {
+            // All implementations must keep all parameters of this method,
+            // including the 'this' parameter.
+            long usedParameters = 1L |
+                                  (parameterMask(libraryClassFile, libraryMethodInfo) << 1);
+
+            // Mark it.
+            markUsedVariables(libraryMethodInfo, usedParameters);
+        }
+    }
+
+
+    // Small utility methods.
+
+    private void markUsedVariables(MethodInfo methodInfo, long usedParameters)
+    {
+        MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(methodInfo);
+        if (info != null)
+        {
+            info.setUsedVariables(info.getUsedVariables() | usedParameters);
+        }
+    }
+
+
+    public static long getUsedVariables(MethodInfo methodInfo)
+    {
+        MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(methodInfo);
+        return info != null ? info.getUsedVariables() : -1L;
+    }
+
+
+    /**
+     * Returns the mask of the parameters on the stack, for the given method,
+     * not including the 'this' parameter, if any.
+     */
+    private int parameterMask(ClassFile classFile, MethodInfo methodInfo)
+    {
+        return (1 << ClassUtil.internalMethodParameterSize(methodInfo.getDescriptor(classFile))) - 1;
+    }
+}
diff --git a/src/proguard/optimize/SideEffectInstructionChecker.java b/src/proguard/optimize/SideEffectInstructionChecker.java
index ae7d569..1eee8b4 100644
--- a/src/proguard/optimize/SideEffectInstructionChecker.java
+++ b/src/proguard/optimize/SideEffectInstructionChecker.java
@@ -1,8 +1,8 @@
-/* $Id: SideEffectInstructionChecker.java,v 1.8 2004/12/11 20:10:10 eric Exp $
+/* $Id: SideEffectInstructionChecker.java,v 1.12 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -41,9 +41,8 @@ public class SideEffectInstructionChecker
 {
     private boolean includeReturnInstructions;
 
-    // Parameters and values for visitor methods.
+    // A return value for the visitor methods.
     private boolean hasSideEffects;
-    private boolean virtual;
 
 
     public SideEffectInstructionChecker(boolean includeReturnInstructions)
@@ -91,8 +90,8 @@ public class SideEffectInstructionChecker
               opcode == InstructionConstants.OP_FRETURN ||
               opcode == InstructionConstants.OP_DRETURN ||
               opcode == InstructionConstants.OP_ARETURN ||
-              opcode == InstructionConstants.OP_RETURN))) {
-
+              opcode == InstructionConstants.OP_RETURN)))
+        {
             // These instructions always cause a side effect.
             hasSideEffects = true;
         }
@@ -119,23 +118,14 @@ public class SideEffectInstructionChecker
 
         // Check for instructions that might cause side effects.
         if      (opcode == InstructionConstants.OP_PUTSTATIC     ||
-                 opcode == InstructionConstants.OP_PUTFIELD)
-        {
-            // Check if the field is write-only.
-            classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
-        }
-        else if (opcode == InstructionConstants.OP_INVOKESPECIAL ||
-                 opcode == InstructionConstants.OP_INVOKESTATIC)
-        {
-            // Check if the invoked method is causing any side effects.
-            virtual = false;
-            classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
-        }
-        else if (opcode == InstructionConstants.OP_INVOKEVIRTUAL ||
+                 opcode == InstructionConstants.OP_PUTFIELD      ||
+                 opcode == InstructionConstants.OP_INVOKEVIRTUAL ||
+                 opcode == InstructionConstants.OP_INVOKESPECIAL ||
+                 opcode == InstructionConstants.OP_INVOKESTATIC  ||
                  opcode == InstructionConstants.OP_INVOKEINTERFACE)
         {
-            // Check if the invoked method is causing any side effects.
-            virtual = true;
+            // Check if the field is write-only, or if the invoked method is
+            // causing any side effects.
             classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
         }
     }
@@ -161,8 +151,10 @@ public class SideEffectInstructionChecker
 
     public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
     {
+        MemberInfo referencedMemberInfo = interfaceMethodrefCpInfo.referencedMemberInfo;
+
         // Do we have a reference to the interface method?
-        if (interfaceMethodrefCpInfo.referencedMemberInfo == null)
+        if (referencedMemberInfo == null)
         {
             // We'll have to assume the unknown interface method has side effects.
             hasSideEffects = true;
@@ -172,24 +164,16 @@ public class SideEffectInstructionChecker
             // First check the referenced interface method itself.
             interfaceMethodrefCpInfo.referencedMemberInfoAccept(this);
 
-            // If the result isn't conclusive, check up and down the hierarchy.
+            // If the result isn't conclusive, check down the hierarchy.
             if (!hasSideEffects)
             {
-                String name = interfaceMethodrefCpInfo.getName(classFile);
-                String type = interfaceMethodrefCpInfo.getType(classFile);
+                ClassFile  referencedClassFile  = interfaceMethodrefCpInfo.referencedClassFile;
+                MethodInfo referencedMethodInfo = (MethodInfo)referencedMemberInfo;
 
                 // Check all implementations of the method.
-                // First go to  all concrete classes of the interface.
-                // From there, travel up and down the class hierarchy to check
-                // the method.
-                //
-                // This way, we're also catching retro-fitted interfaces, where
-                // a class's implementation of an interface method is hiding
-                // higher up its class hierarchy.
-                interfaceMethodrefCpInfo.referencedClassAccept(
-                    new ConcreteClassFileDownTraveler(
-                    new ClassFileHierarchyTraveler(true, true, false, true,
-                    new NamedMethodVisitor(name, type, this))));
+                referencedClassFile.methodImplementationsAccept(referencedMethodInfo,
+                                                                false,
+                                                                this);
             }
         }
     }
@@ -197,8 +181,10 @@ public class SideEffectInstructionChecker
 
     public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
     {
+        MemberInfo referencedMemberInfo = methodrefCpInfo.referencedMemberInfo;
+
         // Do we have a reference to the method?
-        if (methodrefCpInfo.referencedMemberInfo == null)
+        if (referencedMemberInfo == null)
         {
             // We'll have to assume the unknown method has side effects.
             hasSideEffects = true;
@@ -209,17 +195,16 @@ public class SideEffectInstructionChecker
             methodrefCpInfo.referencedMemberInfoAccept(this);
 
             // If the result isn't conclusive, check down the hierarchy.
-            if (!hasSideEffects &&
-                virtual)
+            if (!hasSideEffects)
             {
-                String name = methodrefCpInfo.getName(classFile);
-                String type = methodrefCpInfo.getType(classFile);
-
-                // Check all overriding implementations of the method,
-                // down the class hierarchy.
-                methodrefCpInfo.referencedClassAccept(
-                    new ClassFileHierarchyTraveler(false, false, false, true,
-                    new NamedMethodVisitor(name, type, this)));
+                ClassFile  referencedClassFile  = methodrefCpInfo.referencedClassFile;
+                MethodInfo referencedMethodInfo = (MethodInfo)referencedMemberInfo;
+
+                // Check all other implementations of the method in the class
+                // hierarchy.
+                referencedClassFile.methodImplementationsAccept(referencedMethodInfo,
+                                                                false,
+                                                                this);
             }
         }
     }
diff --git a/src/proguard/optimize/SideEffectMethodMarker.java b/src/proguard/optimize/SideEffectMethodMarker.java
index 982500c..8f6068a 100644
--- a/src/proguard/optimize/SideEffectMethodMarker.java
+++ b/src/proguard/optimize/SideEffectMethodMarker.java
@@ -1,8 +1,8 @@
-/* $Id: SideEffectMethodMarker.java,v 1.3 2004/10/10 20:56:58 eric Exp $
+/* $Id: SideEffectMethodMarker.java,v 1.6 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -39,10 +39,6 @@ public class SideEffectMethodMarker
              MemberInfoVisitor,
              AttrInfoVisitor
 {
-    // A visitor info flag to indicate that a MethodInfo object has side effects.
-    private static final Object SIDE_EFFECTS = new Object();
-
-
     // A reusable object for checking whether instructions have side effects.
     private SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(false);
 
@@ -99,7 +95,7 @@ public class SideEffectMethodMarker
             // Mark the method depending on the return value.
             if (hasSideEffects)
             {
-                markAsSideEffects(programMethodInfo);
+                markSideEffects(programMethodInfo);
 
                 newSideEffectCount++;
             }
@@ -157,16 +153,20 @@ public class SideEffectMethodMarker
 
     // Small utility methods.
 
-    public static void markAsSideEffects(VisitorAccepter visitorAccepter)
+    public static void markSideEffects(MethodInfo methodInfo)
     {
-        visitorAccepter.setVisitorInfo(SIDE_EFFECTS);
+        MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(methodInfo);
+        if (info != null)
+        {
+            info.setSideEffects();
+        }
     }
 
 
-    public static boolean hasSideEffects(VisitorAccepter visitorAccepter)
+    public static boolean hasSideEffects(MethodInfo methodInfo)
     {
-        return visitorAccepter == null                          ||
-               visitorAccepter.getVisitorInfo() == SIDE_EFFECTS ||
-               KeepMarker.isKept(visitorAccepter);
+        MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(methodInfo);
+        return info == null ||
+               info.hasSideEffects();
     }
 }
diff --git a/src/proguard/optimize/peephole/NopRemover.java b/src/proguard/optimize/VariableUsageMarker.java
similarity index 61%
copy from src/proguard/optimize/peephole/NopRemover.java
copy to src/proguard/optimize/VariableUsageMarker.java
index c21bb0f..b3f9858 100644
--- a/src/proguard/optimize/peephole/NopRemover.java
+++ b/src/proguard/optimize/VariableUsageMarker.java
@@ -1,8 +1,8 @@
-/* $Id: NopRemover.java,v 1.5 2004/10/10 20:56:58 eric Exp $
+/* $Id: VariableUsageMarker.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -18,51 +18,57 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-package proguard.optimize.peephole;
+package proguard.optimize;
 
 import proguard.classfile.*;
 import proguard.classfile.attribute.*;
-import proguard.classfile.editor.*;
 import proguard.classfile.instruction.*;
-import proguard.classfile.visitor.*;
 
 /**
- * This InstructionVisitor removes all nop instructions that it encounters.
+ * This InstructionVisitor marks all local variables that are used.
  *
  * @author Eric Lafortune
  */
-public class NopRemover implements InstructionVisitor
+public class VariableUsageMarker
+implements   InstructionVisitor
 {
-    private CodeAttrInfoEditor codeAttrInfoEditor;
-
-
-    /**
-     * Creates a new NopRemover.
-     * @param codeAttrInfoEditor a code editor that can be used for
-     *                           accumulating changes to the code.
-     */
-    public NopRemover(CodeAttrInfoEditor codeAttrInfoEditor)
-    {
-        this.codeAttrInfoEditor = codeAttrInfoEditor;
-    }
-
-
     // Implementations for InstructionVisitor.
 
+    public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
     public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction) {}
-    public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction) {}
     public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
     public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
     public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
 
 
-    public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction)
+    public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction)
+    {
+        markVariableUsed(methodInfo, variableInstruction.variableIndex);
+
+        // Account for Category 2 instructions, which take up two entries.
+        if (variableInstruction.isCategory2())
+        {
+            markVariableUsed(methodInfo, variableInstruction.variableIndex + 1);
+        }
+    }
+
+
+    // Small utility methods.
+
+    public static void markVariableUsed(MethodInfo methodInfo, int variableIndex)
     {
-        // Check if the instruction is a nop instruction.
-        if (simpleInstruction.opcode == InstructionConstants.OP_NOP &&
-            !codeAttrInfoEditor.isModified(offset))
+        MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(methodInfo);
+        if (info != null)
         {
-            codeAttrInfoEditor.deleteInstruction(offset);
+            info.setVariableUsed(variableIndex);
         }
     }
+
+
+    public static boolean isVariableUsed(MethodInfo methodInfo, int variableIndex)
+    {
+        MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(methodInfo);
+        return info == null ||
+               info.isVariableUsed(variableIndex);
+    }
 }
diff --git a/src/proguard/optimize/WriteOnlyFieldMarker.java b/src/proguard/optimize/WriteOnlyFieldMarker.java
index 5d7e773..348fae5 100644
--- a/src/proguard/optimize/WriteOnlyFieldMarker.java
+++ b/src/proguard/optimize/WriteOnlyFieldMarker.java
@@ -1,8 +1,8 @@
-/* $Id: WriteOnlyFieldMarker.java,v 1.5 2004/12/11 16:35:23 eric Exp $
+/* $Id: WriteOnlyFieldMarker.java,v 1.6 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/BranchUnit.java b/src/proguard/optimize/evaluation/BranchUnit.java
index e2f405d..8f9a7ff 100644
--- a/src/proguard/optimize/evaluation/BranchUnit.java
+++ b/src/proguard/optimize/evaluation/BranchUnit.java
@@ -1,8 +1,8 @@
-/* $Id: BranchUnit.java,v 1.3 2004/10/10 20:56:58 eric Exp $
+/* $Id: BranchUnit.java,v 1.4 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/PartialEvaluator.java b/src/proguard/optimize/evaluation/PartialEvaluator.java
index 766ae68..acca7d0 100644
--- a/src/proguard/optimize/evaluation/PartialEvaluator.java
+++ b/src/proguard/optimize/evaluation/PartialEvaluator.java
@@ -1,8 +1,8 @@
-/* $Id: PartialEvaluator.java,v 1.26 2004/12/11 16:35:23 eric Exp $
+/* $Id: PartialEvaluator.java,v 1.32 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -56,18 +56,22 @@ implements   MemberInfoVisitor,
     private static final int INITIAL_CODE_LENGTH = 1024;
     private static final int INITIAL_VALUE_COUNT = 32;
 
-    private static final int MAXIMUM_EVALUATION_COUNT = 100;
-
-
-    private InstructionOffsetValue[] varTraceValues     = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
-    private InstructionOffsetValue[] stackTraceValues   = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
-    private InstructionOffsetValue[] branchOriginValues = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
-    private InstructionOffsetValue[] branchTargetValues = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
-    private TracedVariables[]        vars               = new TracedVariables[INITIAL_CODE_LENGTH];
-    private TracedStack[]            stacks             = new TracedStack[INITIAL_CODE_LENGTH];
-    private int[]                    evaluationCounts   = new int[INITIAL_CODE_LENGTH];
-    private boolean[]                initialization     = new boolean[INITIAL_CODE_LENGTH];
-    private boolean[]                isNecessary        = new boolean[INITIAL_CODE_LENGTH];
+    //private static final int MAXIMUM_EVALUATION_COUNT = 100;
+
+    private static final int AT_METHOD_ENTRY = -1;
+    private static final int AT_CATCH_ENTRY  = -1;
+    private static final int NONE            = -1;
+
+    private InstructionOffsetValue[] varTraceValues      = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
+    private InstructionOffsetValue[] stackTraceValues    = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
+    private InstructionOffsetValue[] unusedTraceValues   = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
+    private InstructionOffsetValue[] branchOriginValues  = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
+    private InstructionOffsetValue[] branchTargetValues  = new InstructionOffsetValue[INITIAL_CODE_LENGTH];
+    private TracedVariables[]        vars                = new TracedVariables[INITIAL_CODE_LENGTH];
+    private TracedStack[]            stacks              = new TracedStack[INITIAL_CODE_LENGTH];
+    private int[]                    evaluationCounts    = new int[INITIAL_CODE_LENGTH];
+    private int[]                    initializedVariable = new int[INITIAL_CODE_LENGTH];
+    private boolean[]                isNecessary         = new boolean[INITIAL_CODE_LENGTH];
     private boolean                  evaluateExceptions;
 
     private TracedVariables  parameters = new TracedVariables(INITIAL_VALUE_COUNT);
@@ -99,11 +103,11 @@ implements   MemberInfoVisitor,
 
         // Count the number of parameters, taking into account their Categories.
         String parameterDescriptor = programMethodInfo.getDescriptor(programClassFile);
-        int count = (isStatic ? 0 : 1) +
+        int parameterSize = (isStatic ? 0 : 1) +
                     ClassUtil.internalMethodParameterSize(parameterDescriptor);
 
         // Reuse the existing parameters object, ensuring the right size.
-        parameters.reset(count);
+        parameters.reset(parameterSize);
 
         // Go over the parameters again.
         InternalTypeEnumeration internalTypeEnumeration =
@@ -112,7 +116,7 @@ implements   MemberInfoVisitor,
         int index = 0;
 
         // Clear the store value of each parameter.
-        parameters.setStoreValue(InstructionOffsetValueFactory.create());
+        parameters.setStoreValue(InstructionOffsetValueFactory.create(AT_METHOD_ENTRY));
 
         // Put the caller's reference in parameter 0.
         if (!isStatic)
@@ -227,27 +231,34 @@ implements   MemberInfoVisitor,
         // branch target.
         if (isNecessary.length < codeLength)
         {
-            varTraceValues     = new InstructionOffsetValue[codeLength];
-            stackTraceValues   = new InstructionOffsetValue[codeLength];
-            branchOriginValues = new InstructionOffsetValue[codeLength];
-            branchTargetValues = new InstructionOffsetValue[codeLength];
-            vars               = new TracedVariables[codeLength];
-            stacks             = new TracedStack[codeLength];
-            evaluationCounts   = new int[codeLength];
-            initialization     = new boolean[codeLength];
-            isNecessary        = new boolean[codeLength];
+            varTraceValues      = new InstructionOffsetValue[codeLength];
+            stackTraceValues    = new InstructionOffsetValue[codeLength];
+            unusedTraceValues   = new InstructionOffsetValue[codeLength];
+            branchOriginValues  = new InstructionOffsetValue[codeLength];
+            branchTargetValues  = new InstructionOffsetValue[codeLength];
+            vars                = new TracedVariables[codeLength];
+            stacks              = new TracedStack[codeLength];
+            evaluationCounts    = new int[codeLength];
+            initializedVariable = new int[codeLength];
+            isNecessary         = new boolean[codeLength];
+
+            for (int index = 0; index < codeLength; index++)
+            {
+                initializedVariable[index] = NONE;
+            }
         }
         else
         {
             for (int index = 0; index < codeLength; index++)
             {
-                varTraceValues[index]     = null;
-                stackTraceValues[index]   = null;
-                branchOriginValues[index] = null;
-                branchTargetValues[index] = null;
-                evaluationCounts[index]   = 0;
-                initialization[index]     = false;
-                isNecessary[index]        = false;
+                varTraceValues[index]      = null;
+                stackTraceValues[index]    = null;
+                unusedTraceValues[index]   = null;
+                branchOriginValues[index]  = null;
+                branchTargetValues[index]  = null;
+                evaluationCounts[index]    = 0;
+                initializedVariable[index] = NONE;
+                isNecessary[index]         = false;
 
                 if (vars[index] != null)
                 {
@@ -306,7 +317,7 @@ implements   MemberInfoVisitor,
         // The invocation of the "super" or "this" <init> method inside a
         // constructor is always necessary, even if it is assumed to have no
         // side effects.
-        boolean markSuperOrThis = 
+        boolean markSuperOrThis =
             methodInfo.getName(classFile).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT);
 
         int aload0Index = 0;
@@ -333,11 +344,11 @@ implements   MemberInfoVisitor,
                          stackTraceValues[index].contains(aload0Index))
                 {
                     markSuperOrThis = false;
-                    
+
                     if (DEBUG_ANALYSIS) System.out.print(index+",");
                     isNecessary[index] = true;
                 }
-                
+
                 // Mark the instruction as necessary if it has side effects.
                 else if (sideEffectInstructionChecker.hasSideEffects(classFile,
                                                                      methodInfo,
@@ -427,8 +438,7 @@ implements   MemberInfoVisitor,
         index = codeLength - 1;
         do
         {
-            if (isTraced(index) &&
-                !isNecessary[index])
+            if (isTraced(index))
             {
                 // Make sure the stack is always consistent at this offset.
                 fixStackConsistency(classFile,
@@ -522,19 +532,20 @@ implements   MemberInfoVisitor,
         // otherwise.
         if (DEBUG_ANALYSIS) System.out.println("Initialization marking: ");
 
-        // TODO: Find a better way.
         index = 0;
         do
         {
-            // Is it an initialization that hasn't been marked yet?
-            if (initialization[index] &&
-                !isNecessary[index])
+            // Is it an initialization that hasn't been marked yet, and whose
+            // corresponding variable is used for storage?
+            int variableIndex = initializedVariable[index];
+            if (variableIndex != NONE &&
+                !isNecessary[index]   &&
+                isVariableReferenced(codeAttrInfo, variableIndex))
             {
                 if (DEBUG_ANALYSIS) System.out.println(index+",");
 
                 // Figure out what kind of initialization value has to be stored.
-                int pushInstructionOffset = stackTraceValues[index].instructionOffset(0);
-                int pushComputationalType = stacks[pushInstructionOffset].getTop(0).computationalType();
+                int pushComputationalType = vars[index].load(variableIndex).computationalType();
                 increaseStackSize(index, pushComputationalType, false);
             }
 
@@ -573,9 +584,13 @@ implements   MemberInfoVisitor,
                     {
                         System.out.println("     is preceded by: "+codeAttrInfoEditor.preInsertions[offset]);
                     }
+                    if (codeAttrInfoEditor.replacements[offset] != null)
+                    {
+                        System.out.println("     is replaced by: "+codeAttrInfoEditor.replacements[offset]);
+                    }
                     if (codeAttrInfoEditor.postInsertions[offset] != null)
                     {
-                        System.out.println("     is followed by: "+codeAttrInfoEditor.preInsertions[offset]);
+                        System.out.println("     is followed by: "+codeAttrInfoEditor.postInsertions[offset]);
                     }
                     System.out.println("     Vars:  "+vars[offset]);
                     System.out.println("     Stack: "+stacks[offset]);
@@ -594,8 +609,11 @@ implements   MemberInfoVisitor,
                                                                 offset);
             if (!isNecessary[offset])
             {
+                codeAttrInfoEditor.deleteInstruction(offset);
+
+                codeAttrInfoEditor.insertBeforeInstruction(offset, null);
                 codeAttrInfoEditor.replaceInstruction(offset, null);
-                codeAttrInfoEditor.replaceInstruction2(offset, null);
+                codeAttrInfoEditor.insertAfterInstruction(offset, null);
             }
 
             offset += instruction.length(offset);
@@ -656,7 +674,8 @@ implements   MemberInfoVisitor,
             {
                 // Has the other instruction been marked yet?
                 int traceOffset = traceOffsetValue.instructionOffset(traceOffsetIndex);
-                if (!isNecessary[traceOffset])
+                if (traceOffset > AT_METHOD_ENTRY &&
+                    !isNecessary[traceOffset])
                 {
                     if (DEBUG_ANALYSIS) System.out.print("["+traceOffset+"]");
 
@@ -925,82 +944,91 @@ implements   MemberInfoVisitor,
                                      CodeAttrInfo codeAttrInfo,
                                      int          index)
     {
-        // Is the unnecessary instruction popping values (but not a dup/swap
-        // instruction)?
-        Instruction popInstruction = InstructionFactory.create(codeAttrInfo.code,
-                                                               index);
-        byte popOpcode = popInstruction.opcode;
-
-        int popCount = popInstruction.stackPopCount(classFile);
-        if (popCount > 0) // &&
-            //popOpcode != InstructionConstants.OP_DUP     &&
-            //popOpcode != InstructionConstants.OP_DUP_X1  &&
-            //popOpcode != InstructionConstants.OP_DUP_X2  &&
-            //popOpcode != InstructionConstants.OP_DUP2    &&
-            //popOpcode != InstructionConstants.OP_DUP2_X1 &&
-            //popOpcode != InstructionConstants.OP_DUP2_X2 &&
-            //popOpcode != InstructionConstants.OP_SWAP)
+        // See if we have any values pushed on the stack that we aren't using.
+        InstructionOffsetValue traceOffsetValue = unusedTraceValues[index];
+
+        // This includes all values if the popping instruction isn't necessary at all.
+        boolean isNotNecessary = !isNecessary[index];
+        if (isNotNecessary)
         {
-            // Check the instructions on which it depends.
-            InstructionOffsetValue traceOffsetValue = stackTraceValues[index];
-            int traceOffsetCount = traceOffsetValue.instructionOffsetCount();
+            traceOffsetValue = traceOffsetValue.generalize(stackTraceValues[index]).instructionOffsetValue();
+        }
 
-            if (popCount <= 4 &&
-                isAllNecessary(traceOffsetValue))
+        // Do we have any pushing instructions?
+        if (traceOffsetValue.instructionOffsetCount() > 0)
+        {
+            // Is this instruction really popping any values?
+            // Note that dup instructions have a pop count of 0.
+            // Also note that method invocations have their original pop counts,
+            // including any unused parameters.
+            Instruction popInstruction = InstructionFactory.create(codeAttrInfo.code,
+                                                                   index);
+            int popCount = popInstruction.stackPopCount(classFile);
+            if (popCount > 0)
             {
-                if (popOpcode == InstructionConstants.OP_POP ||
-                    popOpcode == InstructionConstants.OP_POP2)
+                // Can we pop all values at the popping instruction?
+                if (isNotNecessary &&
+                    popCount <= 6  &&
+                    isAllNecessary(traceOffsetValue))
                 {
-                    if (DEBUG_ANALYSIS) System.out.println("  Popping value again at "+popInstruction.toString(index)+" (pushed at all "+traceOffsetValue.instructionOffsetCount()+" offsets)");
+                    // Is the popping instruction a simple pop or pop2 instruction?
+                    byte popOpcode = popInstruction.opcode;
+                    if (popOpcode == InstructionConstants.OP_POP ||
+                        popOpcode == InstructionConstants.OP_POP2)
+                    {
+                        if (DEBUG_ANALYSIS) System.out.println("  Popping value again at "+popInstruction.toString(index)+" (pushed at all "+traceOffsetValue.instructionOffsetCount()+" offsets)");
 
-                    // Simply mark pop and pop2 instructions.
-                    isNecessary[index] = true;
-                }
-                else
-                {
-                    if (DEBUG_ANALYSIS) System.out.println("  Popping value instead of "+popInstruction.toString(index)+" (pushed at all "+traceOffsetValue.instructionOffsetCount()+" offsets)");
+                        // Simply mark the pop or pop2 instruction.
+                        this.isNecessary[index] = true;
+                    }
+                    else
+                    {
+                        if (DEBUG_ANALYSIS) System.out.println("  Popping value instead of "+popInstruction.toString(index)+" (pushed at all "+traceOffsetValue.instructionOffsetCount()+" offsets)");
 
-                    // Make sure the pushed value is popped again,
-                    // right before this instruction.
-                    decreaseStackSize(index, popCount, true, true);
+                        // Make sure the pushed value is popped again,
+                        // right before this instruction.
+                        decreaseStackSize(index, popCount, true, isNotNecessary);
+                    }
                 }
-            }
-            //else if (popCount == (popInstruction.isCategory2() ? 4 : 2) &&
-            //         traceOffsetCount == 2                              &&
-            //         isAnyNecessary(traceOffsetValue))
-            //{
-            //    if (DEBUG_ANALYSIS) System.out.println("  Popping single value instead of "+popInstruction.toString(index)+" (pushed at some of "+traceOffsetValue.instructionOffsetCount()+" offsets)");
-            //
-            //    // Make sure the single pushed value is popped again,
-            //    // right before this instruction.
-            //    decreaseStackSize(index, popCount / 2, true, true);
-            //}
-            else if (isAnyNecessary(traceOffsetValue))
-            {
-                if (DEBUG_ANALYSIS) System.out.println("  Popping value somewhere before "+index+" (pushed at some of "+traceOffsetValue.instructionOffsetCount()+" offsets):");
-
-                // Go over all stack pushing instructions.
-                for (int traceOffsetIndex = 0; traceOffsetIndex < traceOffsetCount; traceOffsetIndex++)
+                else if (isAnyNecessary(traceOffsetValue))
                 {
-                    // Has the push instruction been marked?
-                    int pushInstructionOffset = traceOffsetValue.instructionOffset(traceOffsetIndex);
-                    if (isNecessary[pushInstructionOffset])
-                    {
-                        Instruction pushInstruction = InstructionFactory.create(codeAttrInfo.code,
-                                                                                pushInstructionOffset);
-
-                        int lastOffset = lastPopInstructionOffset(pushInstructionOffset,
-                                                                  index,
-                                                                  pushInstructionOffset);
-
-                        if (DEBUG_ANALYSIS) System.out.println("    Popping value right after "+lastOffset+", due to push at "+pushInstructionOffset);
+                    // Pop the values right after the pushing instructions.
+                    if (DEBUG_ANALYSIS) System.out.println("  Popping value somewhere before "+index+" (pushed at some of "+traceOffsetValue.instructionOffsetCount()+" offsets):");
 
-                        // Make sure the pushed value is popped again,
-                        // right after the instruction that pushes it
-                        // (or after the dup instruction that still uses it).
-                        decreaseStackSize(lastOffset,
-                                          pushInstruction.stackPushCount(classFile),
-                                          false, false);
+                    // Go over all stack pushing instructions.
+                    int traceOffsetCount = traceOffsetValue.instructionOffsetCount();
+                    for (int traceOffsetIndex = 0; traceOffsetIndex < traceOffsetCount; traceOffsetIndex++)
+                    {
+                        // Has the push instruction been marked?
+                        int pushInstructionOffset = traceOffsetValue.instructionOffset(traceOffsetIndex);
+                        if (this.isNecessary[pushInstructionOffset])
+                        {
+                            Instruction pushInstruction = InstructionFactory.create(codeAttrInfo.code,
+                                                                                    pushInstructionOffset);
+
+                            int lastOffset = lastPopInstructionOffset(pushInstructionOffset,
+                                                                      index,
+                                                                      pushInstructionOffset);
+
+                            if (DEBUG_ANALYSIS) System.out.println("    Popping value right after "+lastOffset+", due to push at "+pushInstructionOffset);
+
+                            // Make sure the pushed value is popped again.
+                            if (lastOffset == AT_METHOD_ENTRY)
+                            {
+                                // Pop it right at the beginning of the method.
+                                decreaseStackSize(0,
+                                                  pushInstruction.stackPushCount(classFile),
+                                                  true, false);
+                            }
+                            else
+                            {
+                                // Pop it right after the instruction that pushes it
+                                // (or after the dup instruction that still uses it).
+                                decreaseStackSize(lastOffset,
+                                                  pushInstruction.stackPushCount(classFile),
+                                                  false, false);
+                            }
+                        }
                     }
                 }
             }
@@ -1024,7 +1052,7 @@ implements   MemberInfoVisitor,
     {
         int lastOffset = startOffset;
 
-        for (int index = startOffset; index < endOffset; index++)
+        for (int index = startOffset + 1; index < endOffset; index++)
         {
             if (isNecessary[index] &&
                 stackTraceValues[index].contains(pushInstructionOffset))
@@ -1040,18 +1068,18 @@ implements   MemberInfoVisitor,
     /**
      * Puts the required push instruction before the given index. The
      * instruction is marked as necessary.
-     * @param index             the offset of the instruction.
+     * @param offset            the offset of the instruction.
      * @param computationalType the computational type on the stack, for
      *                          push instructions.
      * @param delete            specifies whether the instruction should be
      *                          deleted.
      */
-    private void increaseStackSize(int     index,
+    private void increaseStackSize(int     offset,
                                    int     computationalType,
                                    boolean delete)
     {
         // Mark this instruction.
-        isNecessary[index] = true;
+        isNecessary[offset] = true;
 
         // Create a simple push instrucion.
         byte replacementOpcode =
@@ -1065,13 +1093,13 @@ implements   MemberInfoVisitor,
         Instruction replacementInstruction = new SimpleInstruction(replacementOpcode);
 
         // Insert the pop or push instruction.
-        codeAttrInfoEditor.insertBeforeInstruction(index,
+        codeAttrInfoEditor.insertBeforeInstruction(offset,
                                                    replacementInstruction);
 
         // Delete the original instruction if necessary.
         if (delete)
         {
-            codeAttrInfoEditor.deleteInstruction(index);
+            codeAttrInfoEditor.deleteInstruction(offset);
         }
     }
 
@@ -1090,28 +1118,43 @@ implements   MemberInfoVisitor,
                                    boolean before,
                                    boolean delete)
     {
+        // Mark this instruction.
+        isNecessary[offset] = true;
+
         boolean after = !before;
 
-        // Special case: we may replace the instruction by two pop instructions.
-        if (delete && popCount > 2)
+        int remainingPopCount = popCount;
+
+        if (delete)
         {
+            // Replace the original instruction.
+            int count = remainingPopCount == 1 ? 1 : 2;
+
+            // Create a simple pop instrucion.
+            byte replacementOpcode = count == 1 ?
+                InstructionConstants.OP_POP :
+                InstructionConstants.OP_POP2;
+
+            Instruction replacementInstruction = new SimpleInstruction(replacementOpcode);
+
+            // Insert the pop instruction.
+            codeAttrInfoEditor.replaceInstruction(offset,
+                                                  replacementInstruction);
+
+            remainingPopCount -= count;
+
+            // We may insert other pop instructions before and after this one.
             before = true;
             after  = true;
         }
 
-        if (popCount < 1 ||
-            popCount > 4)
+        if (before && remainingPopCount > 0)
         {
-            throw new IllegalArgumentException("Unsupported stack size reduction ["+popCount+"]");
-        }
+            // Insert before the original instruction.
+            int count = remainingPopCount == 1 ? 1 : 2;
 
-        // Mark this instruction.
-        isNecessary[offset] = true;
-
-        if (before)
-        {
             // Create a simple pop instrucion.
-            byte replacementOpcode = popCount == 1 || popCount == 3 ?
+            byte replacementOpcode = count == 1 ?
                 InstructionConstants.OP_POP :
                 InstructionConstants.OP_POP2;
 
@@ -1120,28 +1163,32 @@ implements   MemberInfoVisitor,
             // Insert the pop instruction.
             codeAttrInfoEditor.insertBeforeInstruction(offset,
                                                        replacementInstruction);
+
+            remainingPopCount -= count;
         }
 
-        if (after)
+        if (after && remainingPopCount > 0)
         {
+            // Insert after the original instruction.
+            int count = remainingPopCount == 1 ? 1 : 2;
+
             // Create a simple pop instrucion.
-            byte replacementOpcode = popCount == 1 ?
+            byte replacementOpcode = count == 1 ?
                 InstructionConstants.OP_POP :
                 InstructionConstants.OP_POP2;
 
             Instruction replacementInstruction = new SimpleInstruction(replacementOpcode);
 
-            if (DEBUG_ANALYSIS) System.out.println("    Pop instruction after ["+offset+"]: "+replacementInstruction);
- 
             // Insert the pop instruction.
             codeAttrInfoEditor.insertAfterInstruction(offset,
                                                       replacementInstruction);
+
+            remainingPopCount -= count;
         }
 
-        // Delete the original instruction if necessary.
-        if (delete)
+        if (remainingPopCount > 0)
         {
-            codeAttrInfoEditor.deleteInstruction(offset);
+            throw new IllegalArgumentException("Unsupported stack size reduction ["+popCount+"]");
         }
     }
 
@@ -1275,8 +1322,8 @@ implements   MemberInfoVisitor,
             variables.reset(codeAttrInfo.u2maxLocals);
             stack.reset(codeAttrInfo.u2maxStack);
 
-            // The initial stack doesn't have associated instruction offsets.
-            Value storeValue = InstructionOffsetValueFactory.create();
+            // The initial stack has a generic instruction offset.
+            Value storeValue = InstructionOffsetValueFactory.create(AT_CATCH_ENTRY);
             variables.setStoreValue(storeValue);
             stack.setStoreValue(storeValue);
 
@@ -1364,6 +1411,8 @@ implements   MemberInfoVisitor,
 
         Processor processor = new Processor(variables, stack, branchUnit);
 
+        UnusedParameterCleaner unusedParameterCleaner = new UnusedParameterCleaner(stack);
+
         // Evaluate the subsequent instructions.
         while (true)
         {
@@ -1371,8 +1420,9 @@ implements   MemberInfoVisitor,
             int evaluationCount = evaluationCounts[instructionOffset]++;
             if (evaluationCount == 0)
             {
-                varTraceValues[instructionOffset]   = InstructionOffsetValueFactory.create();
-                stackTraceValues[instructionOffset] = InstructionOffsetValueFactory.create();
+                varTraceValues[instructionOffset]    = InstructionOffsetValueFactory.create();
+                stackTraceValues[instructionOffset]  = InstructionOffsetValueFactory.create();
+                unusedTraceValues[instructionOffset] = InstructionOffsetValueFactory.create();
             }
 
             // Remember this instruction's offset with any stored value.
@@ -1384,6 +1434,7 @@ implements   MemberInfoVisitor,
             InstructionOffsetValue traceValue = InstructionOffsetValueFactory.create();
             variables.setTraceValue(traceValue);
             stack.setTraceValue(traceValue);
+            unusedParameterCleaner.setTraceValue(traceValue);
 
             // Reset the initialization flag.
             variables.resetInitialization();
@@ -1399,6 +1450,13 @@ implements   MemberInfoVisitor,
             branchUnit.resetCalled();
             branchUnit.setTraceBranchTargets(nextInstructionOffsetValue);
 
+            // First clean all traces to unused parameters if this is a method
+            // invocation.
+            instruction.accept(classFile,
+                               methodInfo,
+                               codeAttrInfo,
+                               instructionOffset,
+                               unusedParameterCleaner);
 
             if (DEBUG)
             {
@@ -1410,8 +1468,12 @@ implements   MemberInfoVisitor,
                 // Process the instruction. The processor may call
                 // the Variables methods of 'variables',
                 // the Stack methods of 'stack', and
-                // the BranchUnit methods of this evaluator.
-                instruction.accept(classFile, methodInfo, codeAttrInfo, instructionOffset, processor);
+                // the BranchUnit methods of 'branchUnit'.
+                instruction.accept(classFile,
+                                   methodInfo,
+                                   codeAttrInfo,
+                                   instructionOffset,
+                                   processor);
             }
             catch (RuntimeException ex)
             {
@@ -1426,12 +1488,14 @@ implements   MemberInfoVisitor,
             // Collect the offsets of the instructions whose results were used.
             InstructionOffsetValue variablesTraceValue = variables.getTraceValue().instructionOffsetValue();
             InstructionOffsetValue stackTraceValue     = stack.getTraceValue().instructionOffsetValue();
+            InstructionOffsetValue unusedTraceValue    = unusedParameterCleaner.getTraceValue().instructionOffsetValue();
             varTraceValues[instructionOffset] =
                 varTraceValues[instructionOffset].generalize(variablesTraceValue).instructionOffsetValue();
             stackTraceValues[instructionOffset] =
                 stackTraceValues[instructionOffset].generalize(stackTraceValue).instructionOffsetValue();
-            initialization[instructionOffset] =
-                initialization[instructionOffset] || variables.wasInitialization();
+            unusedTraceValues[instructionOffset] =
+                unusedTraceValues[instructionOffset].generalize(unusedTraceValue).instructionOffsetValue();
+            initializedVariable[instructionOffset] = variables.getInitializationIndex();
 
             // Collect the branch targets from the branch unit.
             InstructionOffsetValue branchTargets = branchUnit.getTraceBranchTargets();
@@ -1465,6 +1529,10 @@ implements   MemberInfoVisitor,
                 {
                     System.out.println("     has up till now been using information from instructions setting stack: "+stackTraceValues[instructionOffset]);
                 }
+                if (unusedTraceValues[instructionOffset].instructionOffsetCount() > 0)
+                {
+                    System.out.println("     no longer needs information from instructions setting stack: "+unusedTraceValues[instructionOffset]);
+                }
                 if (branchTargetValues[instructionOffset] != null)
                 {
                     System.out.println("     has up till now been branching to "+branchTargetValues[instructionOffset]);
@@ -1932,8 +2000,8 @@ implements   MemberInfoVisitor,
 
                     if (DEBUG_ANALYSIS) System.out.println("  Replacing branch instruction at ["+offset+"] by "+replacementInstruction.toString());
 
-                    codeAttrInfoEditor.replaceInstruction2(offset,
-                                                           replacementInstruction);
+                    codeAttrInfoEditor.replaceInstruction(offset,
+                                                          replacementInstruction);
                 }
             }
         }
@@ -1969,14 +2037,14 @@ implements   MemberInfoVisitor,
     private boolean isAnyNecessary(InstructionOffsetValue traceValue)
     {
         int traceCount = traceValue.instructionOffsetCount();
-        if (traceCount == 0)
-        {
-            return true;
-        }
 
         for (int traceIndex = 0; traceIndex < traceCount; traceIndex++)
         {
-            if (isNecessary[traceValue.instructionOffset(traceIndex)])
+            int index = traceValue.instructionOffset(traceIndex);
+
+            if (index == AT_METHOD_ENTRY ||
+                (isNecessary[index] &&
+                 !codeAttrInfoEditor.isModified(index)))
             {
                 return true;
             }
@@ -1993,9 +2061,14 @@ implements   MemberInfoVisitor,
     private boolean isAllNecessary(InstructionOffsetValue traceValue)
     {
         int traceCount = traceValue.instructionOffsetCount();
+
         for (int traceIndex = 0; traceIndex < traceCount; traceIndex++)
         {
-            if (!isNecessary[traceValue.instructionOffset(traceIndex)])
+            int index = traceValue.instructionOffset(traceIndex);
+
+            if (index != AT_METHOD_ENTRY &&
+                (!isNecessary[index] ||
+                 codeAttrInfoEditor.isModified(index)))
             {
                 return false;
             }
@@ -2006,6 +2079,33 @@ implements   MemberInfoVisitor,
 
 
     /**
+     * Returns whether the given variable is ever referenced (stored) by an
+     * instruction that is marked as necessary.
+     */
+    private boolean isVariableReferenced(CodeAttrInfo codeAttrInfo,
+                                         int          variableIndex)
+    {
+        int codeLength = codeAttrInfo.u4codeLength;
+
+        for (int index = 0; index < codeLength; index++)
+        {
+            if (isNecessary[index] &&
+                !codeAttrInfoEditor.isModified(index))
+            {
+                Value traceValue = vars[index].getStoredTraceValue(variableIndex);
+                if (traceValue != null &&
+                    isAnyNecessary(traceValue.instructionOffsetValue()))
+                {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+
+    /**
      * Returns whether the instruction at the given offset has ever been
      * executed during the partial evaluation.
      */
diff --git a/src/proguard/optimize/evaluation/Processor.java b/src/proguard/optimize/evaluation/Processor.java
index 409bea4..3703855 100644
--- a/src/proguard/optimize/evaluation/Processor.java
+++ b/src/proguard/optimize/evaluation/Processor.java
@@ -1,8 +1,8 @@
-/* $Id: Processor.java,v 1.12 2004/12/11 16:35:23 eric Exp $
+/* $Id: Processor.java,v 1.13 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/Stack.java b/src/proguard/optimize/evaluation/Stack.java
index 22b477e..0735010 100644
--- a/src/proguard/optimize/evaluation/Stack.java
+++ b/src/proguard/optimize/evaluation/Stack.java
@@ -1,8 +1,8 @@
-/* $Id: Stack.java,v 1.6 2004/11/20 15:41:24 eric Exp $
+/* $Id: Stack.java,v 1.8 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -181,6 +181,7 @@ class Stack
      * Gets the specified Value from the stack, without disturbing it.
      * @param index the index of the stack element, counting from the bottom
      *              of the stack.
+     * @return the value at the specified position.
      */
     public Value getBottom(int index)
     {
@@ -189,9 +190,22 @@ class Stack
 
 
     /**
+     * Sets the specified Value on the stack, without disturbing it.
+     * @param index the index of the stack element, counting from the bottom
+     *              of the stack.
+     * @param value the value to set.
+     */
+    public void setBottom(int index, Value value)
+    {
+        values[index] = value;
+    }
+
+
+    /**
      * Gets the specified Value from the stack, without disturbing it.
      * @param index the index of the stack element, counting from the top
      *              of the stack.
+     * @return the value at the specified position.
      */
     public Value getTop(int index)
     {
@@ -200,6 +214,18 @@ class Stack
 
 
     /**
+     * Sets the specified Value on the stack, without disturbing it.
+     * @param index the index of the stack element, counting from the top
+     *              of the stack.
+     * @param value the value to set.
+     */
+    public void setTop(int index, Value value)
+    {
+        values[currentSize - index - 1] = value;
+    }
+
+
+    /**
      * Pushes the given Value onto the stack.
      */
     public void push(Value value)
diff --git a/src/proguard/optimize/evaluation/TracedBranchUnit.java b/src/proguard/optimize/evaluation/TracedBranchUnit.java
index 54c922c..990f1f1 100644
--- a/src/proguard/optimize/evaluation/TracedBranchUnit.java
+++ b/src/proguard/optimize/evaluation/TracedBranchUnit.java
@@ -1,8 +1,8 @@
-/* $Id: TracedBranchUnit.java,v 1.3 2004/10/10 20:56:58 eric Exp $
+/* $Id: TracedBranchUnit.java,v 1.5 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -31,8 +31,6 @@ import proguard.optimize.evaluation.value.*;
  */
 class TracedBranchUnit implements BranchUnit
 {
-    private static final boolean DEBUG = true;
-
     private boolean                wasCalled;
     private InstructionOffsetValue traceBranchTargets;
     private Value                  traceReturnValue;
diff --git a/src/proguard/optimize/evaluation/TracedStack.java b/src/proguard/optimize/evaluation/TracedStack.java
index 964a95b..6304fe6 100644
--- a/src/proguard/optimize/evaluation/TracedStack.java
+++ b/src/proguard/optimize/evaluation/TracedStack.java
@@ -1,8 +1,8 @@
-/* $Id: TracedStack.java,v 1.7 2004/11/20 15:06:55 eric Exp $
+/* $Id: TracedStack.java,v 1.9 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -83,6 +83,7 @@ class TracedStack extends Stack
      * Gets the specified trace Value from the stack, without disturbing it.
      * @param index the index of the stack element, counting from the bottom
      *              of the stack.
+     * @return the trace value at the specified position.
      */
     public Value getBottomTraceValue(int index)
     {
@@ -91,9 +92,22 @@ class TracedStack extends Stack
 
 
     /**
+     * Sets the specified trace Value on the stack, without disturbing it.
+     * @param index the index of the stack element, counting from the bottom
+     *              of the stack.
+     * @param value the trace value to set.
+     */
+    public void setBottomTraceValue(int index, Value value)
+    {
+        traceStack.setBottom(index, value);
+    }
+
+
+    /**
      * Gets the specified trace Value from the stack, without disturbing it.
      * @param index the index of the stack element, counting from the top
      *              of the stack.
+     * @return the trace value at the specified position.
      */
     public Value getTopTraceValue(int index)
     {
@@ -101,6 +115,18 @@ class TracedStack extends Stack
     }
 
 
+    /**
+     * Sets the specified trace Value on the stack, without disturbing it.
+     * @param index the index of the stack element, counting from the top
+     *              of the stack.
+     * @param value the trace value to set.
+     */
+    public void setTopTraceValue(int index, Value value)
+    {
+        traceStack.setTop(index, value);
+    }
+
+
     // Implementations for Stack.
 
     public void reset(int size)
diff --git a/src/proguard/optimize/evaluation/TracedVariables.java b/src/proguard/optimize/evaluation/TracedVariables.java
index 77a5a33..8d7dadc 100644
--- a/src/proguard/optimize/evaluation/TracedVariables.java
+++ b/src/proguard/optimize/evaluation/TracedVariables.java
@@ -1,8 +1,8 @@
-/* $Id: TracedVariables.java,v 1.7 2004/11/20 15:06:55 eric Exp $
+/* $Id: TracedVariables.java,v 1.9 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -30,9 +30,8 @@ import proguard.optimize.evaluation.value.*;
  * additional information along with the actual variable values, for instance
  * to keep track of their origins.
  * <p>
- * In addition, a boolean initialization flag can be reset and retrieved,
- * indicating whether store operations on a variable may have initialized the
- * variable.
+ * In addition, an initialization index can be reset and retrieved, pointing
+ * to the most recent variable that has been initialized by a store operation.
  *
  * @author Eric Lafortune
  */
@@ -41,7 +40,7 @@ class TracedVariables extends Variables
     private Variables traceVariables;
     private Value     storeValue;
     private Value     traceValue;
-    private boolean   initialization;
+    private int       initializationIndex;
 
 
     public TracedVariables(int size)
@@ -85,16 +84,38 @@ class TracedVariables extends Variables
 
 
     /**
-     * Resets the initialization flag.
+     * Resets the initialization index.
      */
     public void resetInitialization()
     {
-        initialization = false;
+        initializationIndex = -1;
     }
 
-    public boolean wasInitialization()
+    public int getInitializationIndex()
     {
-        return initialization;
+        return initializationIndex;
+    }
+
+
+    /**
+     * Gets the specified trace Value from the variables, without disturbing them.
+     * @param index the variable index.
+     * @return the trace value at the specified position.
+     */
+    public Value getStoredTraceValue(int index)
+    {
+        return traceVariables.load(index);
+    }
+
+
+    /**
+     * Gets the specified trace Value from the variables, without disturbing them.
+     * @param index the variable index.
+     * @param value the trace value to set.
+     */
+    public void setStoredTraceValue(int index, Value value)
+    {
+        traceVariables.store(index, value);
     }
 
 
@@ -125,10 +146,11 @@ class TracedVariables extends Variables
     {
         // Is this store operation an initialization of the variable?
         Value previousValue = super.load(index);
-        initialization =
-            initialization        ||
-            previousValue == null ||
-            previousValue.computationalType() != value.computationalType();
+        if (previousValue == null ||
+            previousValue.computationalType() != value.computationalType())
+        {
+            initializationIndex = index;
+        }
 
         // Store the value itself in the variable.
         super.store(index, value);
diff --git a/src/proguard/optimize/WriteOnlyFieldMarker.java b/src/proguard/optimize/evaluation/UnusedParameterCleaner.java
similarity index 54%
copy from src/proguard/optimize/WriteOnlyFieldMarker.java
copy to src/proguard/optimize/evaluation/UnusedParameterCleaner.java
index 5d7e773..6a0d689 100644
--- a/src/proguard/optimize/WriteOnlyFieldMarker.java
+++ b/src/proguard/optimize/evaluation/UnusedParameterCleaner.java
@@ -1,8 +1,8 @@
-/* $Id: WriteOnlyFieldMarker.java,v 1.5 2004/12/11 16:35:23 eric Exp $
+/* $Id: UnusedParameterCleaner.java,v 1.4 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -18,31 +18,58 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-package proguard.optimize;
+package proguard.optimize.evaluation;
 
 import proguard.classfile.*;
-import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.CodeAttrInfo;
 import proguard.classfile.instruction.*;
+import proguard.classfile.util.*;
 import proguard.classfile.visitor.*;
-
+import proguard.optimize.*;
+import proguard.optimize.VariableUsageMarker;
+import proguard.optimize.evaluation.value.*;
 
 /**
- * This InstructionVisitor marks all fields that are write-only.
+ * This InstructionVisitor clears the trace values to unused parameters on
+ * the stack, right before the method is being invoked.
  *
+ * @see VariableUsageMarker
  * @author Eric Lafortune
  */
-public class WriteOnlyFieldMarker
-  implements InstructionVisitor,
+public class UnusedParameterCleaner
+implements   InstructionVisitor,
              CpInfoVisitor,
              MemberInfoVisitor
 {
-    // Visitor info flags to indicate whether a FieldInfo object is write-only.
-    private static final Object READ       = new Object();
-    private static final Object WRITE_ONLY = new Object();
+    private static final boolean DEBUG = false;
+
 
+    private TracedStack tracedStack;
+    private Value       traceValue;
 
-    // Parameters and values for visitor methods.
-    private boolean reading;
+
+    /**
+     * Creates a new UnusedParameterCleaner.
+     * @param tracedStack the stack on which trace values can be cleared.
+     */
+    public UnusedParameterCleaner(TracedStack tracedStack)
+    {
+        this.tracedStack = tracedStack;
+    }
+
+
+    /**
+     * Sets the initial Value with which all unused values will be generalized.
+     */
+    public void setTraceValue(Value traceValue)
+    {
+        this.traceValue = traceValue;
+    }
+
+    public Value getTraceValue()
+    {
+        return traceValue;
+    }
 
 
     // Implementations for InstructionVisitor.
@@ -56,23 +83,9 @@ public class WriteOnlyFieldMarker
 
     public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
     {
-        byte opcode = cpInstruction.opcode;
-
-        // Check for instructions that involve fields.
-        if      (opcode == InstructionConstants.OP_GETSTATIC     ||
-                 opcode == InstructionConstants.OP_GETFIELD)
-        {
-            // Mark the field as being read from.
-            reading = true;
-            classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
-        }
-        else if (opcode == InstructionConstants.OP_PUTSTATIC     ||
-                 opcode == InstructionConstants.OP_PUTFIELD)
-        {
-            // Mark the field as being written to.
-            reading = false;
-            classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
-        }
+        // Fix the stack if this is a method invocation of which some
+        // parameters are marked as unused.
+        classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
     }
 
 
@@ -84,75 +97,72 @@ public class WriteOnlyFieldMarker
     public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
     public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
     public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
-    public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
-    public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo) {}
+    public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
     public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo) {}
     public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
 
 
-    public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
+    public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
     {
-        MemberInfo referencedMemberInfo = fieldrefCpInfo.referencedMemberInfo;
-
-        if (referencedMemberInfo != null)
-        {
-            referencedMemberInfo.accept(fieldrefCpInfo.referencedClassFile, this);
-        }
+        interfaceMethodrefCpInfo.referencedMemberInfoAccept(this);
     }
 
 
-    // Implementations for MemberInfoVisitor.
-
-    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+    public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
     {
-        // Hasn't the field been marked as being read yet?
-        if (!isRead(programFieldInfo))
-        {
-            // Mark it now, depending on whther this is a reading operation
-            // or a writing operation.
-            if (reading)
-            {
-                markAsRead(programFieldInfo);
-            }
-            else
-            {
-                markAsWriteOnly(programFieldInfo);
-            }
-        }
+        methodrefCpInfo.referencedMemberInfoAccept(this);
     }
 
 
-    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo) {}
-    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
-    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+    // Implementations for MemberInfoVisitor.
 
+    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
 
-    // Small utility methods.
 
-    private static void markAsRead(VisitorAccepter visitorAccepter)
+    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
-        visitorAccepter.setVisitorInfo(READ);
-    }
+        // Get the used parameters,
+        long usedParameters = ParameterUsageMarker.getUsedVariables(programMethodInfo);
 
+        // Compute the number of parameters.
+        int parameterSize = ClassUtil.internalMethodParameterSize(programMethodInfo.getDescriptor(programClassFile));
 
-    private static boolean isRead(VisitorAccepter visitorAccepter)
-    {
-        return visitorAccepter == null                  ||
-               visitorAccepter.getVisitorInfo() == READ ||
-               KeepMarker.isKept(visitorAccepter);
-    }
+        if ((programMethodInfo.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) == 0)
+        {
+            parameterSize++;
+        }
 
+        // Only consider the 64 first parameters at most.
+        if (parameterSize > 64)
+        {
+            parameterSize = 64;
+        }
 
-    public static void markAsWriteOnly(VisitorAccepter visitorAccepter)
-    {
-        visitorAccepter.setVisitorInfo(WRITE_ONLY);
-    }
+        // Loop over all parameters.
+        for (int index = 0; index < parameterSize; index++)
+        {
+            if ((usedParameters & (1 << index)) == 0)
+            {
+                int stackIndex = parameterSize - index - 1;
 
+                if (traceValue != null)
+                {
+                    traceValue = traceValue.generalize(tracedStack.getTopTraceValue(stackIndex));
+                }
 
-    public static boolean isWriteOnly(VisitorAccepter visitorAccepter)
-    {
-        return visitorAccepter != null                        &&
-               visitorAccepter.getVisitorInfo() == WRITE_ONLY &&
-               !KeepMarker.isKept(visitorAccepter);
+                tracedStack.setTopTraceValue(stackIndex,
+                                             InstructionOffsetValueFactory.create());
+
+                if (DEBUG)
+                {
+                    System.out.println("     clearing reference from unused parameter "+index);
+                    System.out.println("     Stack: "+tracedStack);
+                }
+            }
+        }
     }
+
+
+    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
 }
diff --git a/src/proguard/optimize/evaluation/Variables.java b/src/proguard/optimize/evaluation/Variables.java
index 12070c7..40d5eb5 100644
--- a/src/proguard/optimize/evaluation/Variables.java
+++ b/src/proguard/optimize/evaluation/Variables.java
@@ -1,8 +1,8 @@
-/* $Id: Variables.java,v 1.6 2004/11/20 15:41:24 eric Exp $
+/* $Id: Variables.java,v 1.7 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/Category1Value.java b/src/proguard/optimize/evaluation/value/Category1Value.java
index da9d845..3aaef5b 100644
--- a/src/proguard/optimize/evaluation/value/Category1Value.java
+++ b/src/proguard/optimize/evaluation/value/Category1Value.java
@@ -1,8 +1,8 @@
-/* $Id: Category1Value.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: Category1Value.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/Category2Value.java b/src/proguard/optimize/evaluation/value/Category2Value.java
index eccdef9..6ebd773 100644
--- a/src/proguard/optimize/evaluation/value/Category2Value.java
+++ b/src/proguard/optimize/evaluation/value/Category2Value.java
@@ -1,8 +1,8 @@
-/* $Id: Category2Value.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: Category2Value.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/DoubleValue.java b/src/proguard/optimize/evaluation/value/DoubleValue.java
index ead4ef8..8c90f8b 100644
--- a/src/proguard/optimize/evaluation/value/DoubleValue.java
+++ b/src/proguard/optimize/evaluation/value/DoubleValue.java
@@ -1,8 +1,8 @@
-/* $Id: DoubleValue.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: DoubleValue.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/DoubleValueFactory.java b/src/proguard/optimize/evaluation/value/DoubleValueFactory.java
index 0f5862c..46e19ea 100644
--- a/src/proguard/optimize/evaluation/value/DoubleValueFactory.java
+++ b/src/proguard/optimize/evaluation/value/DoubleValueFactory.java
@@ -1,8 +1,8 @@
-/* $Id: DoubleValueFactory.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: DoubleValueFactory.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/FloatValue.java b/src/proguard/optimize/evaluation/value/FloatValue.java
index 8d5b237..80ae8a6 100644
--- a/src/proguard/optimize/evaluation/value/FloatValue.java
+++ b/src/proguard/optimize/evaluation/value/FloatValue.java
@@ -1,8 +1,8 @@
-/* $Id: FloatValue.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: FloatValue.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/FloatValueFactory.java b/src/proguard/optimize/evaluation/value/FloatValueFactory.java
index 009989a..b897f8c 100644
--- a/src/proguard/optimize/evaluation/value/FloatValueFactory.java
+++ b/src/proguard/optimize/evaluation/value/FloatValueFactory.java
@@ -1,8 +1,8 @@
-/* $Id: FloatValueFactory.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: FloatValueFactory.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/InstructionOffsetValue.java b/src/proguard/optimize/evaluation/value/InstructionOffsetValue.java
index 1f4c20b..072be6d 100644
--- a/src/proguard/optimize/evaluation/value/InstructionOffsetValue.java
+++ b/src/proguard/optimize/evaluation/value/InstructionOffsetValue.java
@@ -1,8 +1,8 @@
-/* $Id: InstructionOffsetValue.java,v 1.6 2004/12/04 19:34:42 eric Exp $
+/* $Id: InstructionOffsetValue.java,v 1.7 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/InstructionOffsetValueFactory.java b/src/proguard/optimize/evaluation/value/InstructionOffsetValueFactory.java
index 2c68cbe..dd0f114 100644
--- a/src/proguard/optimize/evaluation/value/InstructionOffsetValueFactory.java
+++ b/src/proguard/optimize/evaluation/value/InstructionOffsetValueFactory.java
@@ -1,8 +1,8 @@
-/* $Id: InstructionOffsetValueFactory.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: InstructionOffsetValueFactory.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/IntegerValue.java b/src/proguard/optimize/evaluation/value/IntegerValue.java
index 53d245a..24e3385 100644
--- a/src/proguard/optimize/evaluation/value/IntegerValue.java
+++ b/src/proguard/optimize/evaluation/value/IntegerValue.java
@@ -1,8 +1,8 @@
-/* $Id: IntegerValue.java,v 1.3 2004/08/15 12:39:30 eric Exp $
+/* $Id: IntegerValue.java,v 1.4 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/IntegerValueFactory.java b/src/proguard/optimize/evaluation/value/IntegerValueFactory.java
index 19c3e04..b83a09c 100644
--- a/src/proguard/optimize/evaluation/value/IntegerValueFactory.java
+++ b/src/proguard/optimize/evaluation/value/IntegerValueFactory.java
@@ -1,8 +1,8 @@
-/* $Id: IntegerValueFactory.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: IntegerValueFactory.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/LongValue.java b/src/proguard/optimize/evaluation/value/LongValue.java
index e625d38..1fc78e8 100644
--- a/src/proguard/optimize/evaluation/value/LongValue.java
+++ b/src/proguard/optimize/evaluation/value/LongValue.java
@@ -1,8 +1,8 @@
-/* $Id: LongValue.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: LongValue.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/LongValueFactory.java b/src/proguard/optimize/evaluation/value/LongValueFactory.java
index 38475da..0d396ac 100644
--- a/src/proguard/optimize/evaluation/value/LongValueFactory.java
+++ b/src/proguard/optimize/evaluation/value/LongValueFactory.java
@@ -1,8 +1,8 @@
-/* $Id: LongValueFactory.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: LongValueFactory.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/ReferenceValue.java b/src/proguard/optimize/evaluation/value/ReferenceValue.java
index 2d15729..6267052 100644
--- a/src/proguard/optimize/evaluation/value/ReferenceValue.java
+++ b/src/proguard/optimize/evaluation/value/ReferenceValue.java
@@ -1,8 +1,8 @@
-/* $Id: ReferenceValue.java,v 1.3 2004/08/15 12:39:30 eric Exp $
+/* $Id: ReferenceValue.java,v 1.4 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/ReferenceValueFactory.java b/src/proguard/optimize/evaluation/value/ReferenceValueFactory.java
index 30d8da7..da0c2e8 100644
--- a/src/proguard/optimize/evaluation/value/ReferenceValueFactory.java
+++ b/src/proguard/optimize/evaluation/value/ReferenceValueFactory.java
@@ -1,8 +1,8 @@
-/* $Id: ReferenceValueFactory.java,v 1.3 2004/08/15 12:39:30 eric Exp $
+/* $Id: ReferenceValueFactory.java,v 1.5 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -33,6 +33,7 @@ public class ReferenceValueFactory
     // Shared copies of ReferenceValue objects, to avoid creating a lot of objects.
     private static ReferenceValue REFERENCE_VALUE_MAYBE_NULL = new ReferenceValue(true);
     private static ReferenceValue REFERENCE_VALUE_NOT_NULL   = new ReferenceValue(false);
+    private static ReferenceValue REFERENCE_VALUE_NULL       = new SpecificReferenceValue(null, true);
 
 
     /**
@@ -50,7 +51,7 @@ public class ReferenceValueFactory
      */
     public static ReferenceValue createNull()
     {
-        return new SpecificReferenceValue(null, true);
+        return REFERENCE_VALUE_NULL;
     }
 
 
diff --git a/src/proguard/optimize/evaluation/value/SpecificArrayReferenceValue.java b/src/proguard/optimize/evaluation/value/SpecificArrayReferenceValue.java
index 0a4ec34..53a5c22 100644
--- a/src/proguard/optimize/evaluation/value/SpecificArrayReferenceValue.java
+++ b/src/proguard/optimize/evaluation/value/SpecificArrayReferenceValue.java
@@ -1,8 +1,8 @@
-/* $Id: SpecificArrayReferenceValue.java,v 1.4 2004/08/21 21:37:28 eric Exp $
+/* $Id: SpecificArrayReferenceValue.java,v 1.5 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/SpecificDoubleValue.java b/src/proguard/optimize/evaluation/value/SpecificDoubleValue.java
index f957ca6..a61b995 100644
--- a/src/proguard/optimize/evaluation/value/SpecificDoubleValue.java
+++ b/src/proguard/optimize/evaluation/value/SpecificDoubleValue.java
@@ -1,8 +1,8 @@
-/* $Id: SpecificDoubleValue.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: SpecificDoubleValue.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/SpecificFloatValue.java b/src/proguard/optimize/evaluation/value/SpecificFloatValue.java
index b8332a4..229bdb4 100644
--- a/src/proguard/optimize/evaluation/value/SpecificFloatValue.java
+++ b/src/proguard/optimize/evaluation/value/SpecificFloatValue.java
@@ -1,8 +1,8 @@
-/* $Id: SpecificFloatValue.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: SpecificFloatValue.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/SpecificIntegerValue.java b/src/proguard/optimize/evaluation/value/SpecificIntegerValue.java
index 0f21bdf..a596a39 100644
--- a/src/proguard/optimize/evaluation/value/SpecificIntegerValue.java
+++ b/src/proguard/optimize/evaluation/value/SpecificIntegerValue.java
@@ -1,8 +1,8 @@
-/* $Id: SpecificIntegerValue.java,v 1.3 2004/08/15 12:39:30 eric Exp $
+/* $Id: SpecificIntegerValue.java,v 1.4 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/SpecificLongValue.java b/src/proguard/optimize/evaluation/value/SpecificLongValue.java
index 05cc591..c9de331 100644
--- a/src/proguard/optimize/evaluation/value/SpecificLongValue.java
+++ b/src/proguard/optimize/evaluation/value/SpecificLongValue.java
@@ -1,8 +1,8 @@
-/* $Id: SpecificLongValue.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: SpecificLongValue.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/SpecificReferenceValue.java b/src/proguard/optimize/evaluation/value/SpecificReferenceValue.java
index e31c969..6c0b3d1 100644
--- a/src/proguard/optimize/evaluation/value/SpecificReferenceValue.java
+++ b/src/proguard/optimize/evaluation/value/SpecificReferenceValue.java
@@ -1,8 +1,8 @@
-/* $Id: SpecificReferenceValue.java,v 1.4 2004/08/15 12:39:30 eric Exp $
+/* $Id: SpecificReferenceValue.java,v 1.5 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/Value.java b/src/proguard/optimize/evaluation/value/Value.java
index 12affa1..b9855f7 100644
--- a/src/proguard/optimize/evaluation/value/Value.java
+++ b/src/proguard/optimize/evaluation/value/Value.java
@@ -1,8 +1,8 @@
-/* $Id: Value.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: Value.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/evaluation/value/ValueFactory.java b/src/proguard/optimize/evaluation/value/ValueFactory.java
index c4149e6..f622380 100644
--- a/src/proguard/optimize/evaluation/value/ValueFactory.java
+++ b/src/proguard/optimize/evaluation/value/ValueFactory.java
@@ -1,8 +1,8 @@
-/* $Id: ValueFactory.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: ValueFactory.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/BranchTargetFinder.java b/src/proguard/optimize/peephole/BranchTargetFinder.java
index 15bb005..25f04ba 100644
--- a/src/proguard/optimize/peephole/BranchTargetFinder.java
+++ b/src/proguard/optimize/peephole/BranchTargetFinder.java
@@ -1,8 +1,8 @@
-/* $Id: BranchTargetFinder.java,v 1.5 2004/10/10 20:56:58 eric Exp $
+/* $Id: BranchTargetFinder.java,v 1.6 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/ClassFileFinalizer.java b/src/proguard/optimize/peephole/ClassFileFinalizer.java
index 88c1fb2..a8c4bf3 100644
--- a/src/proguard/optimize/peephole/ClassFileFinalizer.java
+++ b/src/proguard/optimize/peephole/ClassFileFinalizer.java
@@ -1,4 +1,4 @@
-/* $Id: ClassFileFinalizer.java,v 1.6 2004/12/19 21:03:13 eric Exp $
+/* $Id: ClassFileFinalizer.java,v 1.7 2004/12/30 16:49:08 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
@@ -71,16 +71,16 @@ public class ClassFileFinalizer
     {
         String name = programMethodInfo.getName(programClassFile);
 
-        // If the method is not final/abstract/private.
-        // and it is not an initialization method,
+        // If the method is not already private/static/final/abstract,
+        // and it is not a constructor,
         // and its class is final,
         //     or it is not being kept and it is not overridden,
         // then make it final.
-        if ((programMethodInfo.u2accessFlags & (ClassConstants.INTERNAL_ACC_FINAL    |
-                                                ClassConstants.INTERNAL_ACC_ABSTRACT |
-                                                ClassConstants.INTERNAL_ACC_PRIVATE)) == 0 &&
-            !name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT)                        &&
-            !name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)                          &&
+        if ((programMethodInfo.u2accessFlags & (ClassConstants.INTERNAL_ACC_PRIVATE |
+                                                ClassConstants.INTERNAL_ACC_STATIC  |
+                                                ClassConstants.INTERNAL_ACC_FINAL   |
+                                                ClassConstants.INTERNAL_ACC_ABSTRACT)) == 0 &&
+            !name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)                         &&
             ((programClassFile.u2accessFlags & ClassConstants.INTERNAL_ACC_FINAL) != 0 ||
              (!KeepMarker.isKept(programMethodInfo) &&
               (programClassFile.subClasses == null ||
diff --git a/src/proguard/optimize/peephole/GetterSetterInliner.java b/src/proguard/optimize/peephole/GetterSetterInliner.java
index caef29c..34f4142 100644
--- a/src/proguard/optimize/peephole/GetterSetterInliner.java
+++ b/src/proguard/optimize/peephole/GetterSetterInliner.java
@@ -1,8 +1,8 @@
-/* $Id: GetterSetterInliner.java,v 1.14 2004/12/18 20:22:42 eric Exp $
+/* $Id: GetterSetterInliner.java,v 1.17 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -39,21 +39,20 @@ implements   InstructionVisitor,
 {
     private static final String SETTER_RETURN_TYPE = "V";
 
-    private ConstantPoolEditor    constantPoolEditor  = new ConstantPoolEditor();
-    private MyGetterSetterChecker getterSetterChecker = new MyGetterSetterChecker();
-    private MemberFinder          memberFinder        = new MemberFinder();
+    private ConstantPoolEditor constantPoolEditor  = new ConstantPoolEditor();
+    private MemberInfoVisitor  getterSetterChecker = new AllAttrInfoVisitor(
+                                                     new MyGetterSetterChecker());
+    private MemberFinder       memberFinder        = new MemberFinder();
 
     private CodeAttrInfoEditor codeAttrInfoEditor;
     private boolean            allowAccessModification;
 
 
     // Return values of the getter/setter checker.
-    private byte        getFieldPutFieldOpcode;
-    private int         referencedClassIndex;
-    private int         referencedFieldIndex;
-    private ClassFile   referencedClassFile;
-    private MemberInfo  referencedFieldInfo;
-    private ClassFile[] typeReferencedClassFiles;
+    private byte       getFieldPutFieldOpcode;
+    private int        referencedFieldIndex;
+    private ClassFile  referencedClassFile;
+    private MemberInfo referencedFieldInfo;
 
 
     /**
@@ -91,7 +90,6 @@ implements   InstructionVisitor,
         {
             // Check if it's a getter or setter that can be inlined.
             getFieldPutFieldOpcode = 0;
-
             classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
 
             // Do we have a getfield or putfield instruction to inline?
@@ -101,12 +99,11 @@ implements   InstructionVisitor,
                 int fieldrefCpInfoIndex = classFile.equals(referencedClassFile) ?
                     referencedFieldIndex :
                     constantPoolEditor.addFieldrefCpInfo((ProgramClassFile)classFile,
-                                                         referencedClassIndex,
+                                                         referencedClassFile.getName(),
                                                          referencedFieldInfo.getName(referencedClassFile),
                                                          referencedFieldInfo.getDescriptor(referencedClassFile),
                                                          referencedClassFile,
-                                                         referencedFieldInfo,
-                                                         typeReferencedClassFiles);
+                                                         referencedFieldInfo);
 
                 // Inline the getfield or putfield instruction.
                 Instruction replacementInstruction = new CpInstruction(getFieldPutFieldOpcode,
@@ -170,9 +167,6 @@ implements   InstructionVisitor,
             return;
         }
 
-        // Remember the constant pool index of the referenced class.
-        referencedClassIndex = methodrefCpInfo.u2classIndex;
-
         // Doesn't the field allow at least the same access as the getter or
         // setter?
         if (AccessUtil.accessLevel(referencedFieldInfo.getAccessFlags()) <
@@ -182,7 +176,7 @@ implements   InstructionVisitor,
             if (allowAccessModification)
             {
                 // Is the field access private, and is the field shadowed by
-                // a field in a subclass?
+                // a non-private field in a subclass?
                 if (AccessUtil.accessLevel(referencedFieldInfo.getAccessFlags()) == AccessUtil.PRIVATE &&
                     memberFinder.isShadowed(referencedClassFile, (FieldInfo)referencedFieldInfo))
                 {
@@ -213,25 +207,10 @@ implements   InstructionVisitor,
      * getter or setter.
      */
     private class MyGetterSetterChecker
-    implements    MemberInfoVisitor,
-                  AttrInfoVisitor,
+    implements    AttrInfoVisitor,
                   InstructionVisitor,
                   CpInfoVisitor
     {
-        // Implementations for MemberInfoVisitor.
-
-        public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
-
-        public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
-        {
-            programMethodInfo.attributesAccept(programClassFile, this);
-        }
-
-
-        public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
-        public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
-
-
         // Implementations for AttrInfoVisitor.
 
         public void visitUnknownAttrInfo(ClassFile classFile, UnknownAttrInfo unknownAttrInfo) {}
@@ -365,6 +344,7 @@ implements   InstructionVisitor,
         public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo) {}
         public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
         public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo) {}
+        public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
 
 
         public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
@@ -372,16 +352,6 @@ implements   InstructionVisitor,
             // Remember the class file and the field.
             referencedClassFile = fieldrefCpInfo.referencedClassFile;
             referencedFieldInfo = fieldrefCpInfo.referencedMemberInfo;
-
-            // Retrieve the referenced class files.
-            classFile.constantPoolEntryAccept(fieldrefCpInfo.u2nameAndTypeIndex, this);
-        }
-
-
-        public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
-        {
-            // Remember the referenced class files of the field.
-            typeReferencedClassFiles = nameAndTypeCpInfo.referencedClassFiles;
         }
     }
 }
diff --git a/src/proguard/optimize/peephole/GotoReturnReplacer.java b/src/proguard/optimize/peephole/GotoReturnReplacer.java
index c472e2d..42d6e6c 100644
--- a/src/proguard/optimize/peephole/GotoReturnReplacer.java
+++ b/src/proguard/optimize/peephole/GotoReturnReplacer.java
@@ -1,8 +1,8 @@
-/* $Id: GotoReturnReplacer.java,v 1.6 2004/11/20 15:06:55 eric Exp $
+/* $Id: GotoReturnReplacer.java,v 1.7 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/LoadStoreRemover.java b/src/proguard/optimize/peephole/LoadStoreRemover.java
index a4619f4..c98c01d 100644
--- a/src/proguard/optimize/peephole/LoadStoreRemover.java
+++ b/src/proguard/optimize/peephole/LoadStoreRemover.java
@@ -1,8 +1,8 @@
-/* $Id: LoadStoreRemover.java,v 1.6 2004/10/10 20:56:58 eric Exp $
+/* $Id: LoadStoreRemover.java,v 1.8 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -21,10 +21,9 @@
 package proguard.optimize.peephole;
 
 import proguard.classfile.*;
-import proguard.classfile.attribute.*;
-import proguard.classfile.editor.*;
+import proguard.classfile.attribute.CodeAttrInfo;
+import proguard.classfile.editor.CodeAttrInfoEditor;
 import proguard.classfile.instruction.*;
-import proguard.classfile.visitor.*;
 
 /**
  * This InstructionVisitor deletes load/store instruction pairs.
@@ -68,8 +67,7 @@ public class LoadStoreRemover implements InstructionVisitor
         if (variableInstruction.isLoad() &&
             variableInstruction.opcode != InstructionConstants.OP_RET)
         {
-            byte opcode        = variableInstruction.opcode;
-            int  variableIndex = variableInstruction.variableIndex;
+            int variableIndex = variableInstruction.variableIndex;
 
             int nextOffset = offset + variableInstruction.length(offset);
 
diff --git a/src/proguard/optimize/NoSideEffectMethodMarker.java b/src/proguard/optimize/peephole/MethodPrivatizer.java
similarity index 53%
copy from src/proguard/optimize/NoSideEffectMethodMarker.java
copy to src/proguard/optimize/peephole/MethodPrivatizer.java
index 2b69044..0578abd 100644
--- a/src/proguard/optimize/NoSideEffectMethodMarker.java
+++ b/src/proguard/optimize/peephole/MethodPrivatizer.java
@@ -1,8 +1,8 @@
-/* $Id: NoSideEffectMethodMarker.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: MethodPrivatizer.java,v 1.5 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -18,57 +18,41 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-package proguard.optimize;
+package proguard.optimize.peephole;
 
 import proguard.classfile.*;
-import proguard.classfile.instruction.*;
-import proguard.classfile.visitor.*;
+import proguard.classfile.util.AccessUtil;
+import proguard.classfile.visitor.MemberInfoVisitor;
+import proguard.optimize.NonPrivateMethodMarker;
 
 /**
- * This MemberInfoVisitor marks all methods that it visits as not having any side
- * effects. It will make the SideEffectMethodMarker consider them as such
- * without further analysis.
+ * This MemberInfoVisitor makes all final methods that it visits private,
+ * unless they have been marked by a NonPrivateMethodMarker.
  *
- * @see SideEffectMethodMarker
+ * @see NonPrivateMethodMarker
  * @author Eric Lafortune
  */
-public class NoSideEffectMethodMarker
+public class MethodPrivatizer
   implements MemberInfoVisitor
 {
-    // A visitor info flag to indicate that a MethodInfo object doesn't have
-    // anyside effects.
-    private static final Object NO_SIDE_EFFECTS = new Object();
-
-
     // Implementations for MemberInfoVisitor.
 
     public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
 
     public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
-        markAsNoSideEffects(programMethodInfo);
+        int accessFlags = programMethodInfo.getAccessFlags();
+
+        // Is the method unmarked?
+        if (NonPrivateMethodMarker.canBeMadePrivate(programMethodInfo))
+        {
+            // Make the method private.
+            programMethodInfo.u2accessFlags =
+                AccessUtil.replaceAccessFlags(accessFlags,
+                                              ClassConstants.INTERNAL_ACC_PRIVATE);
+        }
     }
 
-
     public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
-
-    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
-    {
-        markAsNoSideEffects(libraryMethodInfo);
-    }
-
-
-    // Small utility methods.
-
-    public static void markAsNoSideEffects(VisitorAccepter visitorAccepter)
-    {
-        visitorAccepter.setVisitorInfo(NO_SIDE_EFFECTS);
-    }
-
-
-    public static boolean hasNoSideEffects(VisitorAccepter visitorAccepter)
-    {
-        return visitorAccepter != null &&
-               visitorAccepter.getVisitorInfo() == NO_SIDE_EFFECTS;
-    }
+    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
 }
diff --git a/src/proguard/optimize/peephole/NopRemover.java b/src/proguard/optimize/peephole/NopRemover.java
index c21bb0f..e018f25 100644
--- a/src/proguard/optimize/peephole/NopRemover.java
+++ b/src/proguard/optimize/peephole/NopRemover.java
@@ -1,8 +1,8 @@
-/* $Id: NopRemover.java,v 1.5 2004/10/10 20:56:58 eric Exp $
+/* $Id: NopRemover.java,v 1.6 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/PushPopRemover.java b/src/proguard/optimize/peephole/PushPopRemover.java
index c342f68..16394e9 100644
--- a/src/proguard/optimize/peephole/PushPopRemover.java
+++ b/src/proguard/optimize/peephole/PushPopRemover.java
@@ -1,8 +1,8 @@
-/* $Id: PushPopRemover.java,v 1.8 2004/10/10 20:56:58 eric Exp $
+/* $Id: PushPopRemover.java,v 1.9 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/optimize/peephole/SingleImplementationFixer.java b/src/proguard/optimize/peephole/SingleImplementationFixer.java
new file mode 100644
index 0000000..d9c156e
--- /dev/null
+++ b/src/proguard/optimize/peephole/SingleImplementationFixer.java
@@ -0,0 +1,181 @@
+/* $Id: SingleImplementationFixer.java,v 1.3 2005/06/11 13:21:35 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.optimize.peephole;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.editor.*;
+import proguard.classfile.editor.ConstantPoolEditor;
+import proguard.classfile.visitor.*;
+
+/**
+ * This ClassFileVisitor cleans up after the SingleImplementationInliner.
+ * It fixes the names of interfaces that have single implementations, lets
+ * the implementations and fields references point to them again. This is
+ * necessary after the SingleImplementationInliner has overzealously renamed
+ * the interfaces to the single implementations, let the single implementations
+ * point to themselves as interfaces, and let the field references point to the
+ * single implementations.
+ *
+ * @see SingleImplementationInliner
+ * @see ClassFileReferenceFixer
+ * @author Eric Lafortune
+ */
+public class SingleImplementationFixer
+implements   ClassFileVisitor,
+             CpInfoVisitor
+{
+    private ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor();
+
+
+    // Implementations for ClassFileVisitor.
+
+    public void visitProgramClassFile(ProgramClassFile programClassFile)
+    {
+        // Is this an interface with a single implementation?
+        ClassFile singleImplementationClassFile =
+            SingleImplementationMarker.singleImplementation(programClassFile);
+
+        if (singleImplementationClassFile != null)
+        {
+            // Fix the reference to its own name.
+            fixThisClassReference(programClassFile);
+
+            // Fix the reference from its single interface or implementation.
+            fixInterfaceReference((ProgramClassFile)programClassFile.subClasses[0],
+                                  programClassFile);
+        }
+
+        // Fix the field references in the constant pool.
+        programClassFile.constantPoolEntriesAccept(this);
+    }
+
+
+    public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+    {
+    }
+
+
+    // Implementations for CpInfoVisitor.
+
+    public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+    public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+    public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+    public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+    public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo) {}
+    public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+    public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo) {}
+    public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo) {}
+    public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo) {}
+    public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+
+
+    public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
+    {
+        // Update the referenced class file if it is an interface with a single
+        // implementation.
+        ClassFile singleImplementationClassFile =
+            SingleImplementationMarker.singleImplementation(fieldrefCpInfo.referencedClassFile);
+
+        if (singleImplementationClassFile != null)
+        {
+            // Fix the reference to the interface.
+            fixFieldrefClassReference((ProgramClassFile)classFile,
+                                      fieldrefCpInfo);
+        }
+    }
+
+
+    // Small utility methods.
+
+    /**
+     * Fixes the given class file, so its name points to itself again.
+     */
+    private void fixThisClassReference(ProgramClassFile programClassFile)
+    {
+        // We have to add a new class entry to avoid an existing entry with the
+        // same name being reused. The names have to be fixed later, based on
+        // their referenced class files.
+        int nameIndex =
+            constantPoolEditor.addUtf8CpInfo(programClassFile,
+                                             programClassFile.getName());
+        programClassFile.u2thisClass =
+            constantPoolEditor.addCpInfo(programClassFile,
+                                         new ClassCpInfo(nameIndex,
+                                                         programClassFile));
+    }
+
+
+    /**
+     * Fixes the given class file, so it points to the given interface again.
+     */
+    private void fixInterfaceReference(ProgramClassFile programClassFile,
+                                       ProgramClassFile interfaceClassFile)
+    {
+        // Make sure the class refers to the given interface again.
+        String interfaceName = interfaceClassFile.getName();
+
+        int interfacesCount = programClassFile.u2interfacesCount;
+        for (int index = 0; index < interfacesCount; index++)
+        {
+            if (interfaceName.equals(programClassFile.getInterfaceName(index)))
+            {
+                // Update the class index.
+                // We have to add a new class entry to avoid an existing entry
+                // with the same name being reused. The names have to be fixed
+                // later, based on their referenced class files.
+                int nameIndex =
+                    constantPoolEditor.addUtf8CpInfo(programClassFile,
+                                                     interfaceName);
+                programClassFile.u2interfaces[index] =
+                    constantPoolEditor.addCpInfo(programClassFile,
+                                                 new ClassCpInfo(nameIndex,
+                                                                 interfaceClassFile));
+                break;
+
+            }
+        }
+    }
+
+
+    /**
+     * Fixes the given field reference, so its class index points to its
+     * class again. Note that this could be a different class than the one
+     * in the original class file.
+     */
+    private void fixFieldrefClassReference(ProgramClassFile programClassFile,
+                                           FieldrefCpInfo   fieldrefCpInfo)
+    {
+        ClassFile referencedClassFile = fieldrefCpInfo.referencedClassFile;
+
+        // We have to add a new class entry to avoid an existing entry with the
+        // same name being reused. The names have to be fixed later, based on
+        // their referenced class files.
+        int nameIndex =
+            constantPoolEditor.addUtf8CpInfo(programClassFile,
+                                             fieldrefCpInfo.getClassName(programClassFile));
+        fieldrefCpInfo.u2classIndex =
+            constantPoolEditor.addCpInfo(programClassFile,
+                                         new ClassCpInfo(nameIndex,
+                                                         referencedClassFile));
+    }
+}
diff --git a/src/proguard/optimize/peephole/SingleImplementationInliner.java b/src/proguard/optimize/peephole/SingleImplementationInliner.java
index c700199..c26f3d8 100644
--- a/src/proguard/optimize/peephole/SingleImplementationInliner.java
+++ b/src/proguard/optimize/peephole/SingleImplementationInliner.java
@@ -1,8 +1,8 @@
-/* $Id: SingleImplementationInliner.java,v 1.7 2004/12/11 16:35:23 eric Exp $
+/* $Id: SingleImplementationInliner.java,v 1.10 2005/06/26 16:20:23 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -23,66 +23,134 @@ package proguard.optimize.peephole;
 import proguard.classfile.*;
 import proguard.classfile.attribute.*;
 import proguard.classfile.attribute.annotation.*;
-import proguard.classfile.editor.*;
-import proguard.classfile.instruction.*;
-import proguard.classfile.util.*;
+import proguard.classfile.editor.ClassFileReferenceFixer;
 import proguard.classfile.visitor.*;
 
 /**
- * This MemberInfoVisitor and AttrInfoVisitor replaces all references to
- * interfaces that have single implementations by references to those
- * implementations.
+ * This ClassFileVisitor replaces all references to interfaces that have single
+ * implementations by references to those implementations. The names will then
+ * have to be fixed, based on the new references.
  *
+ * @see SingleImplementationFixer
+ * @see ClassFileReferenceFixer
  * @author Eric Lafortune
  */
 public class SingleImplementationInliner
-implements   MemberInfoVisitor,
-             AttrInfoVisitor,
-             InstructionVisitor,
+implements   ClassFileVisitor,
              CpInfoVisitor,
+             MemberInfoVisitor,
+             AttrInfoVisitor,
              LocalVariableInfoVisitor,
-             LocalVariableTypeInfoVisitor
+             LocalVariableTypeInfoVisitor,
+             AnnotationVisitor,
+             ElementValueVisitor
 {
-    private MemberFinder memberFinder = new MemberFinder();
+    // Implementations for ClassFileVisitor.
 
-    private ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor();
-    private CodeAttrInfoEditor codeAttrInfoEditor = new CodeAttrInfoEditor(1024);
+    public void visitProgramClassFile(ProgramClassFile programClassFile)
+    {
+        // Update the constant pool.
+        programClassFile.constantPoolEntriesAccept(this);
 
+        // Update the class members.
+        programClassFile.fieldsAccept(this);
+        programClassFile.methodsAccept(this);
 
-    // Return values of the single implementation inliner.
-    private int       cpIndex;
-    private ClassFile singleImplementationClassFile;
+        // Update the attributes.
+        programClassFile.attributesAccept(this);
+    }
 
 
-    // Implementations for MemberInfoVisitor.
+    public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+    {
+    }
 
-    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+
+    // Implementations for CpInfoVisitor.
+
+    public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
+    public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
+    public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
+    public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
+    public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
+    public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo) {}
+    public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo) {}
+    public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo) {}
+
+
+    public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
     {
-        visitMemberInfo(programClassFile, programFieldInfo);
+        // Update the referenced class file if it is an interface with a single
+        // implementation.
+        ClassFile singleImplementationClassFile =
+            SingleImplementationMarker.singleImplementation(stringCpInfo.referencedClassFile);
+
+        if (singleImplementationClassFile != null)
+        {
+            stringCpInfo.referencedClassFile = singleImplementationClassFile;
+        }
     }
 
-    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+
+    public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
     {
-        visitMemberInfo(programClassFile, programMethodInfo);
+        // Update the referenced interface if it has a single implementation.
+        ClassFile singleImplementationClassFile =
+            SingleImplementationMarker.singleImplementation(interfaceMethodrefCpInfo.referencedClassFile);
+
+        if (singleImplementationClassFile != null)
+        {
+            // We know the single implementation contains the method.
+            String name = interfaceMethodrefCpInfo.getName(classFile);
+            String type = interfaceMethodrefCpInfo.getType(classFile);
+
+            interfaceMethodrefCpInfo.referencedClassFile  = singleImplementationClassFile;
+            interfaceMethodrefCpInfo.referencedMemberInfo = singleImplementationClassFile.findMethod(name, type);
+        }
     }
 
-    private void visitMemberInfo(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+
+    public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
     {
-        // Update the member info if any of its referenced classes
-        // is an interface with a single implementation.
-        ClassFile[] referencedClassFiles =
-            updateReferencedClassFiles(programMemberInfo.referencedClassFiles);
+        // Update the referenced class file if it is an interface with a single
+        // implementation.
+        ClassFile singleImplementationClassFile =
+            SingleImplementationMarker.singleImplementation(classCpInfo.referencedClassFile);
 
-        // Update the descriptor if necessary.
-        if (referencedClassFiles != null)
+        if (singleImplementationClassFile != null)
         {
-            programMemberInfo.u2descriptorIndex =
-                constantPoolEditor.addUtf8CpInfo(programClassFile,
-                                                 newDescriptor(programMemberInfo.getDescriptor(programClassFile),
-                                                               referencedClassFiles));
+            classCpInfo.referencedClassFile = singleImplementationClassFile;
+        }
+    }
+
 
-            programMemberInfo.referencedClassFiles = referencedClassFiles;
+    // Implementations for MemberInfoVisitor.
+
+    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+    {
+        // Update the referenced class file if the type is an interface with a
+        // single implementation.
+        ClassFile singleImplementationClassFile =
+            SingleImplementationMarker.singleImplementation(programFieldInfo.referencedClassFile);
+
+        if (singleImplementationClassFile != null)
+        {
+            programFieldInfo.referencedClassFile = singleImplementationClassFile;
         }
+
+        // Update the attributes.
+        programFieldInfo.attributesAccept(programClassFile, this);
+    }
+
+
+    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+    {
+        // Update the referenced class files if the descriptor contains
+        // interfaces with single implementations.
+        updateReferencedClassFiles(programMethodInfo.referencedClassFiles);
+
+        // Update the attributes.
+        programMethodInfo.attributesAccept(programClassFile, this);
     }
 
 
@@ -106,429 +174,162 @@ implements   MemberInfoVisitor,
 
     public void visitCodeAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo)
     {
-        // Reset the code changes.
-        codeAttrInfoEditor.reset(codeAttrInfo.u4codeLength);
-
-        // Update the instructions that refer to interfaces with a single
-        // implementation.
-        codeAttrInfo.instructionsAccept(classFile, methodInfo, this);
-
-        // Apply the code changes.
-        codeAttrInfoEditor.visitCodeAttrInfo(classFile, methodInfo, codeAttrInfo);
-
-        //codeAttrInfo.attributesAccept(classFile, methodInfo, this);
+        // Update the referenced class files of the local variables.
+        codeAttrInfo.attributesAccept(classFile, methodInfo, this);
     }
 
 
     public void visitLocalVariableTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTableAttrInfo localVariableTableAttrInfo)
     {
-        // Rename the types of the local variables.
+        // Update the referenced class files of the local variables.
         localVariableTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
     }
 
 
     public void visitLocalVariableTypeTableAttrInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeTableAttrInfo localVariableTypeTableAttrInfo)
     {
-        // Rename the signatures of the local variables.
+        // Update the referenced class files of the local variable types.
         localVariableTypeTableAttrInfo.localVariablesAccept(classFile, methodInfo, codeAttrInfo, this);
     }
 
 
     public void visitSignatureAttrInfo(ClassFile classFile, SignatureAttrInfo signatureAttrInfo)
     {
-        // TODO: Update signature attribute.
+        // Update the referenced class files.
+        updateReferencedClassFiles(signatureAttrInfo.referencedClassFiles);
     }
 
 
     public void visitRuntimeVisibleAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleAnnotationsAttrInfo runtimeVisibleAnnotationsAttrInfo)
     {
-        // TODO: Update runtime visible annotation attribute.
-
-        //runtimeVisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+        // Update the annotations.
+        runtimeVisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
     }
 
 
     public void visitRuntimeInvisibleAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleAnnotationsAttrInfo runtimeInvisibleAnnotationsAttrInfo)
     {
-        // TODO: Update runtime invisible annotation attribute.
-
-        //runtimeInvisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
+        // Update the annotations.
+        runtimeInvisibleAnnotationsAttrInfo.annotationsAccept(classFile, this);
     }
 
 
     public void visitRuntimeVisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeVisibleParameterAnnotationsAttrInfo runtimeVisibleParameterAnnotationsAttrInfo)
     {
-        // TODO: Update runtime visible parameter annotation attribute.
-
-        //runtimeVisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+        // Update the annotations.
+        runtimeVisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
     }
 
 
     public void visitRuntimeInvisibleParameterAnnotationAttrInfo(ClassFile classFile, RuntimeInvisibleParameterAnnotationsAttrInfo runtimeInvisibleParameterAnnotationsAttrInfo)
     {
-        // TODO: Update runtime invisible parameter annotation attribute.
-
-        //runtimeInvisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
+        // Update the annotations.
+        runtimeInvisibleParameterAnnotationsAttrInfo.annotationsAccept(classFile, this);
     }
 
 
     public void visitAnnotationDefaultAttrInfo(ClassFile classFile, AnnotationDefaultAttrInfo annotationDefaultAttrInfo)
     {
-        // TODO: Update annotation default attribute.
-
-        //annotationDefaultAttrInfo.defaultValueAccept(classFile, this);
+        // Update the annotation.
+        annotationDefaultAttrInfo.defaultValueAccept(classFile, this);
     }
 
 
-    // Implementations for InstructionVisitor.
-
-    public void visitSimpleInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, SimpleInstruction simpleInstruction) {}
-    public void visitVariableInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, VariableInstruction variableInstruction) {}
-    public void visitBranchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, BranchInstruction branchInstruction) {}
-    public void visitTableSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, TableSwitchInstruction tableSwitchInstruction) {}
-    public void visitLookUpSwitchInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) {}
-
+    // Implementations for LocalVariableInfoVisitor.
 
-    public void visitCpInstruction(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, int offset, CpInstruction cpInstruction)
+    public void visitLocalVariableInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableInfo localVariableInfo)
     {
-        cpIndex = 0;
-        classFile.constantPoolEntryAccept(cpInstruction.cpIndex, this);
+        // Update the referenced class file if it is an interface with a single
+        // implementation.
+        ClassFile singleImplementationClassFile =
+            SingleImplementationMarker.singleImplementation(localVariableInfo.referencedClassFile);
 
-        if (cpIndex != 0)
+        if (singleImplementationClassFile != null)
         {
-            byte opcode = cpInstruction.opcode;
-
-            // Does this instruction now invoke a single implementation?
-            if (opcode == InstructionConstants.OP_INVOKEINTERFACE &&
-                singleImplementationClassFile != null)
-            {
-                // Replace the interface invocation by an ordinary invocation.
-                opcode = InstructionConstants.OP_INVOKEVIRTUAL;
-            }
-
-            // Replace the instruction by an updated instruction.
-            Instruction replacementInstruction = new CpInstruction(opcode,
-                                                                   cpIndex,
-                                                                   cpInstruction.constant).shrink();
-
-            codeAttrInfoEditor.replaceInstruction(offset, replacementInstruction);
+            localVariableInfo.referencedClassFile = singleImplementationClassFile;
         }
     }
 
 
-    // Implementations for CpInfoVisitor.
-
-    public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo) {}
-    public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo) {}
-    public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo) {}
-    public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo) {}
-    public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo) {}
-
+    // Implementations for LocalVariableTypeInfoVisitor.
 
-    public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
+    public void visitLocalVariableTypeInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeInfo localVariableTypeInfo)
     {
-        // Create a new string entry if its referenced class is an interface with
-        // a single implementation.
-        singleImplementationClassFile =
-            SingleImplementationMarker.singleImplementation(stringCpInfo.referencedClassFile);
-
-        if (singleImplementationClassFile != null)
-        {
-            // Create a new string entry.
-            cpIndex = constantPoolEditor.addStringCpInfo((ProgramClassFile)classFile,
-                                                         singleImplementationClassFile.getName(),
-                                                         singleImplementationClassFile);
-        }
+        // Update the referenced class files.
+        updateReferencedClassFiles(localVariableTypeInfo.referencedClassFiles);
     }
 
 
-    public void visitFieldrefCpInfo(ClassFile classFile, FieldrefCpInfo fieldrefCpInfo)
-    {
-        // Create a new field reference entry if its type has changed.
-        cpIndex = 0;
-        classFile.constantPoolEntryAccept(fieldrefCpInfo.getNameAndTypeIndex(), this);
-        int nameAndTypeIndex = cpIndex;
-
-        if (nameAndTypeIndex != 0)
-        {
-            // Create a new field reference entry.
-            cpIndex = constantPoolEditor.addFieldrefCpInfo((ProgramClassFile)classFile,
-                                                           fieldrefCpInfo.getClassIndex(),
-                                                           nameAndTypeIndex,
-                                                           fieldrefCpInfo.referencedClassFile,
-                                                           fieldrefCpInfo.referencedMemberInfo);
-        }
-    }
-
+    // Implementations for AnnotationVisitor.
 
-    public void visitMethodrefCpInfo(ClassFile classFile, MethodrefCpInfo methodrefCpInfo)
+    public void visitAnnotation(ClassFile classFile, Annotation annotation)
     {
-        // Create a new method reference entry if its type has changed.
-        cpIndex = 0;
-        classFile.constantPoolEntryAccept(methodrefCpInfo.getNameAndTypeIndex(), this);
-        int nameAndTypeIndex = cpIndex;
+        // Update the referenced class files.
+        updateReferencedClassFiles(annotation.referencedClassFiles);
 
-        if (nameAndTypeIndex != 0)
-        {
-            // Create a new method reference entry.
-            cpIndex = constantPoolEditor.addMethodrefCpInfo((ProgramClassFile)classFile,
-                                                            methodrefCpInfo.getClassIndex(),
-                                                            nameAndTypeIndex,
-                                                            methodrefCpInfo.referencedClassFile,
-                                                            methodrefCpInfo.referencedMemberInfo);
-        }
+        // Update the element values.
+        annotation.elementValuesAccept(classFile, this);
     }
 
 
-    public void visitInterfaceMethodrefCpInfo(ClassFile classFile, InterfaceMethodrefCpInfo interfaceMethodrefCpInfo)
-    {
-        // Create a new ordinary method reference entry, if its referenced class
-        // is an interface with a single implementation, or a a new interface
-        // method reference entry, if its type has changed.
-        cpIndex = 0;
-        classFile.constantPoolEntryAccept(interfaceMethodrefCpInfo.getClassIndex(), this);
-        int classIndex = cpIndex;
-
-        cpIndex = 0;
-        classFile.constantPoolEntryAccept(interfaceMethodrefCpInfo.getNameAndTypeIndex(), this);
-        int nameAndTypeIndex = cpIndex;
-
-        if (classIndex != 0)
-        {
-            if (nameAndTypeIndex == 0)
-            {
-                nameAndTypeIndex = interfaceMethodrefCpInfo.getNameAndTypeIndex();
-            }
-
-            // See if we can find the referenced method.
-            ClassFile referencedClassFile = singleImplementationClassFile;
-
-            String name = interfaceMethodrefCpInfo.getName(classFile);
-            String type = interfaceMethodrefCpInfo.getType(classFile);
+    // Implementations for ElementValueVisitor.
 
-            // See if we can find the referenced class membver somewhere in the
-            // hierarchy.
-            MethodInfo referencedMethodInfo = memberFinder.findMethod(referencedClassFile,
-                                                                      name,
-                                                                      type);
-            referencedClassFile             = memberFinder.correspondingClassFile();
-
-            // Create an ordinary method reference entry.
-            cpIndex = constantPoolEditor.addMethodrefCpInfo((ProgramClassFile)classFile,
-                                                            classIndex,
-                                                            nameAndTypeIndex,
-                                                            referencedClassFile,
-                                                            referencedMethodInfo);
-        }
-        else if (nameAndTypeIndex != 0)
-        {
-            classIndex = interfaceMethodrefCpInfo.getClassIndex();
-
-            // Create an interface method reference entry.
-            cpIndex = constantPoolEditor.addInterfaceMethodrefCpInfo((ProgramClassFile)classFile,
-                                                                     classIndex,
-                                                                     nameAndTypeIndex,
-                                                                     interfaceMethodrefCpInfo.referencedClassFile,
-                                                                     interfaceMethodrefCpInfo.referencedMemberInfo);
-        }
+    public void visitConstantElementValue(ClassFile classFile, Annotation annotation, ConstantElementValue constantElementValue)
+    {
     }
 
 
-    public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
+    public void visitEnumConstantElementValue(ClassFile classFile, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
     {
-        // Create a new class entry if its referenced class is an interface with
-        // a single implementation.
-        singleImplementationClassFile =
-            SingleImplementationMarker.singleImplementation(classCpInfo.referencedClassFile);
-
-        if (singleImplementationClassFile != null)
-        {
-            // Create a new class entry.
-            cpIndex = constantPoolEditor.addClassCpInfo((ProgramClassFile)classFile,
-                                                        newClassName(classCpInfo.getName(classFile),
-                                                                     singleImplementationClassFile),
-                                                        singleImplementationClassFile);
-        }
+        // Update the referenced class files.
+        updateReferencedClassFiles(enumConstantElementValue.referencedClassFiles);
     }
 
 
-    public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
+    public void visitClassElementValue(ClassFile classFile, Annotation annotation, ClassElementValue classElementValue)
     {
-        // Create a new name and type entry if any of the referenced classes of
-        // its type is an interface with a single implementation.
-        ClassFile[] referencedClassFiles =
-            updateReferencedClassFiles(nameAndTypeCpInfo.referencedClassFiles);
-
-        if (referencedClassFiles != null)
-        {
-            // Create a new name and type entry.
-            cpIndex = constantPoolEditor.addNameAndTypeCpInfo((ProgramClassFile)classFile,
-                                                              nameAndTypeCpInfo.getName(classFile),
-                                                              newDescriptor(nameAndTypeCpInfo.getType(classFile),
-                                                                            referencedClassFiles),
-                                                              referencedClassFiles);
-        }
+        // Update the referenced class files.
+        updateReferencedClassFiles(classElementValue.referencedClassFiles);
     }
 
 
-    // Implementations for LocalVariableInfoVisitor.
-
-    public void visitLocalVariableInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableInfo localVariableInfo)
+    public void visitAnnotationElementValue(ClassFile classFile, Annotation annotation, AnnotationElementValue annotationElementValue)
     {
-        // Create a new type entry if its referenced class is an interface with
-        // a single implementation.
-        ClassFile singleImplementationClassFile =
-            SingleImplementationMarker.singleImplementation(localVariableInfo.referencedClassFile);
-
-        // Update the type if necessary.
-        if (singleImplementationClassFile != null)
-        {
-            // Refer to a new Utf8 entry.
-            localVariableInfo.u2descriptorIndex =
-                constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
-                                                 newClassName(classFile.getCpString(localVariableInfo.u2descriptorIndex),
-                                                              singleImplementationClassFile));
-        }
+        // Update the annotation.
+        annotationElementValue.annotationAccept(classFile, this);
     }
 
 
-    // Implementations for LocalVariableTypeInfoVisitor.
-
-    public void visitLocalVariableTypeInfo(ClassFile classFile, MethodInfo methodInfo, CodeAttrInfo codeAttrInfo, LocalVariableTypeInfo localVariableTypeInfo)
+    public void visitArrayElementValue(ClassFile classFile, Annotation annotation, ArrayElementValue arrayElementValue)
     {
-        // Create a new signature entry if any of the referenced classes of
-        // its type is an interface with a single implementation.
-        ClassFile[] referencedClassFiles =
-            updateReferencedClassFiles(localVariableTypeInfo.referencedClassFiles);
-
-        // Update the signature if necessary.
-        if (referencedClassFiles != null)
-        {
-            localVariableTypeInfo.u2signatureIndex =
-                constantPoolEditor.addUtf8CpInfo((ProgramClassFile)classFile,
-                                                 newDescriptor(classFile.getCpString(localVariableTypeInfo.u2signatureIndex),
-                                                               referencedClassFiles));
-        }
+        // Update the element values.
+        arrayElementValue.elementValuesAccept(classFile, annotation, this);
     }
 
 
     // Small utility methods.
 
     /**
-     * Updates the given array of referenced class files, if the refer to an
-     * interface with a single implementation. Returns a new array if it
-     * needed to be updated, or <code>null</code> otherwise.
+     * Updates the given array of referenced class files, replacing references
+     * to a interfaces with single implementations by these implementations.
      */
-    private ClassFile[] updateReferencedClassFiles(ClassFile[] referencedClassFiles)
+    private void updateReferencedClassFiles(ClassFile[] referencedClassFiles)
     {
-        ClassFile[] newReferencedClassFiles = null;
-
-        // Check all referenced classes.
-        if (referencedClassFiles != null &&
-            referencedClassFilesChanged(referencedClassFiles))
+        // Update all referenced classes.
+        if (referencedClassFiles != null)
         {
-            // Create a new array to copy the elements.
-            newReferencedClassFiles = new ClassFile[referencedClassFiles.length];
-
-            // Update all referenced classes.
             for (int index = 0; index < referencedClassFiles.length; index++)
             {
-                ClassFile referencedClassFile = referencedClassFiles[index];
-
                 // See if we have is an interface with a single implementation.
                 ClassFile singleImplementationClassFile =
-                    SingleImplementationMarker.singleImplementation(referencedClassFile);
+                    SingleImplementationMarker.singleImplementation(referencedClassFiles[index]);
 
                 // Update or copy the referenced class file.
-                newReferencedClassFiles[index] = singleImplementationClassFile != null ?
-                    singleImplementationClassFile :
-                    referencedClassFile;
-            }
-        }
-
-        return newReferencedClassFiles;
-    }
-
-
-    private boolean referencedClassFilesChanged(ClassFile[] referencedClassFiles)
-    {
-        // Check all referenced classes.
-        for (int index = 0; index < referencedClassFiles.length; index++)
-        {
-            // See if we have is an interface with a single implementation.
-            if (SingleImplementationMarker.singleImplementation(referencedClassFiles[index]) != null)
-            {
-                // We've found an element that needs to be updated.
-                return true;
+                if (singleImplementationClassFile != null)
+                {
+                    referencedClassFiles[index] = singleImplementationClassFile;
+                }
             }
         }
-
-        return false;
-    }
-
-
-    /**
-     * Returns the new descriptor based on the given descriptor and the new
-     * names of the given referenced class files.
-     */
-    private String newDescriptor(String      descriptor,
-                                 ClassFile[] referencedClassFiles)
-    {
-        // Unravel and reconstruct the class elements of the descriptor.
-        DescriptorClassEnumeration descriptorClassEnumeration =
-            new DescriptorClassEnumeration(descriptor);
-
-        String newDescriptor = descriptorClassEnumeration.nextFluff();
-
-        int index = 0;
-        while (descriptorClassEnumeration.hasMoreClassNames())
-        {
-            String className = descriptorClassEnumeration.nextClassName();
-            String fluff     = descriptorClassEnumeration.nextFluff();
-
-            String newClassName = newClassName(className,
-                                               referencedClassFiles[index++]);
-
-            // Fall back on the original class name if there is no new name.
-            if (newClassName == null)
-            {
-                newClassName = className;
-            }
-
-            newDescriptor = newDescriptor + newClassName + fluff;
-        }
-
-        return newDescriptor;
-    }
-
-
-    /**
-     * Returns the new class name based on the given class name and the new
-     * name of the given referenced class file. Class names of array types
-     * are handled properly.
-     */
-    private String newClassName(String    className,
-                                ClassFile referencedClassFile)
-    {
-        // If there is no new class name, the descriptor doesn't change.
-        if (referencedClassFile == null)
-        {
-            return className;
-        }
-
-        // Reconstruct the class name.
-        String newClassName = referencedClassFile.getName();
-
-        // Is it an array type?
-        if (className.charAt(0) == ClassConstants.INTERNAL_TYPE_ARRAY)
-        {
-            // Add the array prefixes and suffix "[L...;".
-            newClassName =
-                 className.substring(0, className.indexOf(ClassConstants.INTERNAL_TYPE_CLASS_START)+1) +
-                 newClassName +
-                 ClassConstants.INTERNAL_TYPE_CLASS_END;
-        }
-
-        return newClassName;
     }
 }
diff --git a/src/proguard/optimize/peephole/SingleImplementationMarker.java b/src/proguard/optimize/peephole/SingleImplementationMarker.java
index 472fe4c..520e0d7 100644
--- a/src/proguard/optimize/peephole/SingleImplementationMarker.java
+++ b/src/proguard/optimize/peephole/SingleImplementationMarker.java
@@ -1,8 +1,8 @@
-/* $Id: SingleImplementationMarker.java,v 1.3 2004/11/20 15:41:24 eric Exp $
+/* $Id: SingleImplementationMarker.java,v 1.7 2005/06/26 16:20:23 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -36,9 +36,7 @@ import proguard.optimize.*;
 public class SingleImplementationMarker
 implements   ClassFileVisitor
 {
-    // A visitor info flag to indicate that a ClassFile object is the single
-    // implementation of an interface.
-    private static final Object SINGLE_IMPLEMENTATION = new Object();
+    private static final boolean DEBUG = false;
 
 
     private boolean allowAccessModification;
@@ -93,10 +91,17 @@ implements   ClassFileVisitor
             singleImplementationAccessFlags = singleImplementationClassFile.getAccessFlags();
         }
 
-        // The single implementation must not be abstract.
-        else if ((singleImplementationAccessFlags & ClassConstants.INTERNAL_ACC_ABSTRACT) != 0)
+        // The single implementation must contain all non-static methods of this
+        // interface, so invocations can easily be diverted.
+        for (int index = 0; index < programClassFile.u2methodsCount; index++)
         {
-            return;
+            MethodInfo method = programClassFile.methods[index];
+            if ((method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) == 0 &&
+                singleImplementationClassFile.findMethod(method.getName(programClassFile),
+                                                         method.getDescriptor(programClassFile)) == null)
+            {
+                return;
+            }
         }
 
         // Doesn't the implementation have at least the same access as the
@@ -120,6 +125,11 @@ implements   ClassFileVisitor
             }
         }
 
+        if (DEBUG)
+        {
+            System.out.println("Single implementation of ["+programClassFile.getName()+"]: ["+singleImplementationClassFile.getName()+"]");
+        }
+
         // Mark the interface and its single implementation.
         markSingleImplementation(programClassFile, singleImplementationClassFile);
     }
@@ -133,13 +143,8 @@ implements   ClassFileVisitor
     public static void markSingleImplementation(VisitorAccepter visitorAccepter,
                                                 ClassFile       singleImplementation)
     {
-        //System.out.println("Marking single implementation ["+((ClassFile)visitorAccepter).getName()+"] -> ["+singleImplementation.getName()+"]");
-
         // The interface has a single implementation.
         visitorAccepter.setVisitorInfo(singleImplementation);
-
-        // The class is a single implementation.
-        singleImplementation.setVisitorInfo(SINGLE_IMPLEMENTATION);
     }
 
 
@@ -150,11 +155,4 @@ implements   ClassFileVisitor
                    (ClassFile)visitorAccepter.getVisitorInfo() :
                    null;
     }
-
-
-    public static boolean isSingleImplementation(VisitorAccepter visitorAccepter)
-    {
-        return visitorAccepter != null &&
-               visitorAccepter.getVisitorInfo() == SINGLE_IMPLEMENTATION;
-    }
 }
diff --git a/src/proguard/optimize/peephole/StoreLoadReplacer.java b/src/proguard/optimize/peephole/StoreLoadReplacer.java
index 74e62f9..c2aad40 100644
--- a/src/proguard/optimize/peephole/StoreLoadReplacer.java
+++ b/src/proguard/optimize/peephole/StoreLoadReplacer.java
@@ -1,8 +1,8 @@
-/* $Id: StoreLoadReplacer.java,v 1.7 2004/11/20 15:06:55 eric Exp $
+/* $Id: StoreLoadReplacer.java,v 1.9 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -21,10 +21,9 @@
 package proguard.optimize.peephole;
 
 import proguard.classfile.*;
-import proguard.classfile.attribute.*;
-import proguard.classfile.editor.*;
+import proguard.classfile.attribute.CodeAttrInfo;
+import proguard.classfile.editor.CodeAttrInfoEditor;
 import proguard.classfile.instruction.*;
-import proguard.classfile.visitor.*;
 
 /**
  * This InstructionVisitor replaces store/load instruction pairs by equivalent
diff --git a/src/proguard/retrace/ReTrace.java b/src/proguard/retrace/ReTrace.java
index b981572..6bad1e2 100644
--- a/src/proguard/retrace/ReTrace.java
+++ b/src/proguard/retrace/ReTrace.java
@@ -1,8 +1,8 @@
-/* $Id: ReTrace.java,v 1.7 2004/08/15 12:39:30 eric Exp $
+/* $Id: ReTrace.java,v 1.10 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -20,7 +20,7 @@
  */
 package proguard.retrace;
 
-import java.io.IOException;
+import java.io.*;
 
 import proguard.obfuscate.MappingReader;
 
@@ -38,41 +38,40 @@ public class ReTrace
 
     // The class settings.
     private boolean verbose;
-    private String  mappingFileName;
-    private String  stackTraceFileName;
+    private File    mappingFile;
+    private File    stackTraceFile;
 
 
     /**
      * Creates a new ReTrace object to process stack traces on the standard
      * input, based on the given mapping file name.
-     * @param verbose         specifies whether the de-obfuscated stack trace
-     *                        should be verbose.
-     * @param mappingFileName the mapping file that was written out by ProGuard.
+     * @param verbose     specifies whether the de-obfuscated stack trace
+     *                    should be verbose.
+     * @param mappingFile the mapping file that was written out by ProGuard.
      */
     public ReTrace(boolean verbose,
-                   String  mappingFileName)
+                   File    mappingFile)
     {
-        this(verbose, mappingFileName, null);
+        this(verbose, mappingFile, null);
     }
 
 
     /**
      * Creates a new ReTrace object to process a stack trace from the given file,
      * based on the given mapping file name.
-     * @param verbose            specifies whether the de-obfuscated stack trace
-     *                           should be verbose.
-     * @param mappingFileName    the mapping file that was written out by
-     *                           ProGuard.
-     * @param stackTraceFileName the name of the file that contains the stack
-     *                           trace.
+     * @param verbose        specifies whether the de-obfuscated stack trace
+     *                       should be verbose.
+     * @param mappingFile    the mapping file that was written out by ProGuard.
+     * @param stackTraceFile the optional name of the file that contains the
+     *                       stack trace.
      */
     public ReTrace(boolean verbose,
-                   String  mappingFileName,
-                   String  stackTraceFileName)
+                   File    mappingFile,
+                   File    stackTraceFile)
     {
-        this.verbose            = verbose;
-        this.mappingFileName    = mappingFileName;
-        this.stackTraceFileName = stackTraceFileName;
+        this.verbose        = verbose;
+        this.mappingFile    = mappingFile;
+        this.stackTraceFile = stackTraceFile;
     }
 
 
@@ -82,10 +81,10 @@ public class ReTrace
     public void execute() throws IOException
     {
         StackTrace stackTrace = new StackTrace(verbose);
-        MappingReader reader = new MappingReader(mappingFileName);
+        MappingReader reader = new MappingReader(mappingFile);
 
         // Read the obfuscated stack trace.
-        stackTrace.read(stackTraceFileName);
+        stackTrace.read(stackTraceFile);
 
         // Resolve the obfuscated stack trace by means of the mapping file.
         reader.pump(stackTrace);
@@ -121,14 +120,13 @@ public class ReTrace
             }
         }
 
-        String mappingFileName    = args[argumentIndex++];
-        String stackTraceFileName = argumentIndex < args.length ?
-            args[argumentIndex++] :
+        File mappingFile    = new File(args[argumentIndex++]);
+        File stackTraceFile = argumentIndex < args.length ?
+            new File(args[argumentIndex++]) :
             null;
 
-        ReTrace reTrace = new ReTrace(verbose,
-                                      mappingFileName,
-                                      stackTraceFileName);
+        ReTrace reTrace = new ReTrace(verbose, mappingFile, stackTraceFile);
+
         try
         {
             // Execute ReTrace with its given settings.
diff --git a/src/proguard/retrace/StackTrace.java b/src/proguard/retrace/StackTrace.java
index 50961c9..45097d2 100644
--- a/src/proguard/retrace/StackTrace.java
+++ b/src/proguard/retrace/StackTrace.java
@@ -1,8 +1,8 @@
-/* $Id: StackTrace.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: StackTrace.java,v 1.8 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -55,15 +55,15 @@ class StackTrace implements MappingProcessor
     /**
      * Reads the stack trace file.
      */
-    public void read(String stackTraceFileName) throws IOException
+    public void read(File stackTraceFile) throws IOException
     {
         LineNumberReader lineNumberReader = null;
 
         try
         {
-            Reader reader = stackTraceFileName == null ?
+            Reader reader = stackTraceFile == null ?
                 (Reader)new InputStreamReader(System.in) :
-                (Reader)new BufferedReader(new FileReader(stackTraceFileName));
+                (Reader)new BufferedReader(new FileReader(stackTraceFile));
 
             lineNumberReader = new LineNumberReader(reader);
 
@@ -96,7 +96,7 @@ class StackTrace implements MappingProcessor
         }
         finally
         {
-            if (stackTraceFileName != null &&
+            if (stackTraceFile != null &&
                 lineNumberReader != null)
             {
                 try
diff --git a/src/proguard/retrace/StackTraceItem.java b/src/proguard/retrace/StackTraceItem.java
index f3e30c3..4031aae 100644
--- a/src/proguard/retrace/StackTraceItem.java
+++ b/src/proguard/retrace/StackTraceItem.java
@@ -1,8 +1,8 @@
-/* $Id: StackTraceItem.java,v 1.7 2004/08/15 12:39:30 eric Exp $
+/* $Id: StackTraceItem.java,v 1.9 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -141,7 +141,7 @@ class StackTraceItem implements MappingProcessor
         int spaceIndex = line.lastIndexOf(' ', colonIndex);
 
         prefix              = line.substring(0, spaceIndex+1);
-        obfuscatedClassName = line.substring(spaceIndex+1, colonIndex).trim();;
+        obfuscatedClassName = line.substring(spaceIndex+1, colonIndex).trim();
         suffix              = line.substring(colonIndex);
 
         return true;
diff --git a/src/proguard/shrink/ClassFileShrinker.java b/src/proguard/shrink/ClassFileShrinker.java
index 5d5be32..4525057 100644
--- a/src/proguard/shrink/ClassFileShrinker.java
+++ b/src/proguard/shrink/ClassFileShrinker.java
@@ -1,8 +1,8 @@
-/* $Id: ClassFileShrinker.java,v 1.25 2004/12/04 23:43:43 eric Exp $
+/* $Id: ClassFileShrinker.java,v 1.27 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -41,18 +41,25 @@ public class ClassFileShrinker
              MemberInfoVisitor,
              AttrInfoVisitor
 {
-    private int[]                cpIndexMap;
+    private UsageMarker          usageMarker;
     private ConstantPoolRemapper constantPoolRemapper;
+    private int[]                cpIndexMap;
 
 
     /**
      * Creates a new ClassFileShrinker.
+    /**
+     * Creates a new InnerUsageMarker.
+     * @param usageMarker the usage marker that is used to mark the classes
+     *                    and class members.
      * @param codeLength an estimate of the maximum length of all the code that
      *                   will be edited.
      */
-    public ClassFileShrinker(int codeLength)
+    public ClassFileShrinker(UsageMarker usageMarker,
+                             int         codeLength)
     {
-        constantPoolRemapper = new ConstantPoolRemapper(codeLength);
+        this.usageMarker          = usageMarker;
+        this.constantPoolRemapper = new ConstantPoolRemapper(codeLength);
     }
 
 
@@ -186,7 +193,7 @@ public class ClassFileShrinker
         // a constructor of javax.swing.JList, but it is also referenced as a
         // dummy argument in a constructor of javax.swing.JList$ListSelectionHandler.
         if (enclosingMethodAttrInfo.referencedMethodInfo != null &&
-            !UsageMarker.isUsed(enclosingMethodAttrInfo.referencedMethodInfo))
+            !usageMarker.isUsed(enclosingMethodAttrInfo.referencedMethodInfo))
         {
             enclosingMethodAttrInfo.u2nameAndTypeIndex = 0;
 
@@ -232,7 +239,7 @@ public class ClassFileShrinker
             // Don't update the flag if this is the second half of a long entry.
             if (cpInfo != null)
             {
-                isUsed = UsageMarker.isUsed(cpInfo);
+                isUsed = usageMarker.isUsed(cpInfo);
             }
 
             if (isUsed)
@@ -256,14 +263,14 @@ public class ClassFileShrinker
      * from the given array.
      * @return the new number of indices.
      */
-    private static int shrinkCpIndexArray(CpInfo[] constantPool, int[] array, int length)
+    private int shrinkCpIndexArray(CpInfo[] constantPool, int[] array, int length)
     {
         int counter = 0;
 
         // Shift the used objects together.
         for (int index = 0; index < length; index++)
         {
-            if (UsageMarker.isUsed(constantPool[array[index]]))
+            if (usageMarker.isUsed(constantPool[array[index]]))
             {
                 array[counter++] = array[index];
             }
@@ -285,7 +292,7 @@ public class ClassFileShrinker
      * of the right size.
      * @return the new array.
      */
-    private static ClassFile[] shrinkToNewArray(ClassFile[] array)
+    private ClassFile[] shrinkToNewArray(ClassFile[] array)
     {
         if (array == null)
         {
@@ -317,14 +324,14 @@ public class ClassFileShrinker
      * from the given array.
      * @return the new number of VisitorAccepter objects.
      */
-    private static int shrinkArray(VisitorAccepter[] array, int length)
+    private int shrinkArray(VisitorAccepter[] array, int length)
     {
         int counter = 0;
 
         // Shift the used objects together.
         for (int index = 0; index < length; index++)
         {
-            if (UsageMarker.isUsed(array[index]))
+            if (usageMarker.isUsed(array[index]))
             {
                 array[counter++] = array[index];
             }
diff --git a/src/proguard/shrink/InnerUsageMarker.java b/src/proguard/shrink/InnerUsageMarker.java
index 26ae15a..43b6166 100644
--- a/src/proguard/shrink/InnerUsageMarker.java
+++ b/src/proguard/shrink/InnerUsageMarker.java
@@ -1,8 +1,8 @@
-/* $Id: InnerUsageMarker.java,v 1.15 2004/12/11 16:35:23 eric Exp $
+/* $Id: InnerUsageMarker.java,v 1.18 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -40,15 +40,31 @@ public class InnerUsageMarker
              AttrInfoVisitor,
              InnerClassesInfoVisitor
 {
+    private UsageMarker usageMarker;
+
+    // A field acting as a parameter for the class file visitor.
     private boolean markingAttributes = true;
+
+    // A field acting as a return parameter for several methods.
     private boolean used;
 
 
+    /**
+     * Creates a new InnerUsageMarker.
+     * @param usageMarker the usage marker that is used to mark the classes
+     *                    and class members.
+     */
+    public InnerUsageMarker(UsageMarker usageMarker)
+    {
+        this.usageMarker = usageMarker;
+    }
+
+
     // Implementations for ClassFileVisitor.
 
     public void visitProgramClassFile(ProgramClassFile programClassFile)
     {
-        boolean classUsed = UsageMarker.isUsed(programClassFile);
+        boolean classUsed = usageMarker.isUsed(programClassFile);
 
         if (markingAttributes && classUsed)
         {
@@ -87,7 +103,7 @@ public class InnerUsageMarker
 
     public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
     {
-        boolean classUsed = UsageMarker.isUsed(classCpInfo);
+        boolean classUsed = usageMarker.isUsed(classCpInfo);
 
         if (!classUsed)
         {
@@ -100,7 +116,7 @@ public class InnerUsageMarker
             {
                 // The class is being used. Mark the ClassCpInfo as being used
                 // as well.
-                UsageMarker.markAsUsed(classCpInfo);
+                usageMarker.markAsUsed(classCpInfo);
 
                 markCpEntry(classFile, classCpInfo.u2nameIndex);
             }
@@ -113,9 +129,9 @@ public class InnerUsageMarker
 
     public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo)
     {
-        if (!UsageMarker.isUsed(utf8CpInfo))
+        if (!usageMarker.isUsed(utf8CpInfo))
         {
-            UsageMarker.markAsUsed(utf8CpInfo);
+            usageMarker.markAsUsed(utf8CpInfo);
         }
     }
 
@@ -158,7 +174,7 @@ public class InnerUsageMarker
         {
             // We got a positive used flag, so some inner class is being used.
             // Mark this attribute as being used as well.
-            UsageMarker.markAsUsed(innerClassesAttrInfo);
+            usageMarker.markAsUsed(innerClassesAttrInfo);
 
             markCpEntry(classFile, innerClassesAttrInfo.u2attrNameIndex);
         }
@@ -169,7 +185,7 @@ public class InnerUsageMarker
 
     public void visitInnerClassesInfo(ClassFile classFile, InnerClassesInfo innerClassesInfo)
     {
-        boolean innerClassesInfoUsed = UsageMarker.isUsed(innerClassesInfo);
+        boolean innerClassesInfoUsed = usageMarker.isUsed(innerClassesInfo);
 
         if (!innerClassesInfoUsed)
         {
@@ -197,7 +213,7 @@ public class InnerUsageMarker
             // used, then mark this InnerClassesInfo as well.
             if (innerClassesInfoUsed)
             {
-                UsageMarker.markAsUsed(innerClassesInfo);
+                usageMarker.markAsUsed(innerClassesInfo);
 
                 if (u2innerNameIndex != 0)
                 {
diff --git a/src/proguard/shrink/InterfaceUsageMarker.java b/src/proguard/shrink/InterfaceUsageMarker.java
index d8c84da..c35ade1 100644
--- a/src/proguard/shrink/InterfaceUsageMarker.java
+++ b/src/proguard/shrink/InterfaceUsageMarker.java
@@ -1,8 +1,8 @@
-/* $Id: InterfaceUsageMarker.java,v 1.10 2004/12/11 16:35:23 eric Exp $
+/* $Id: InterfaceUsageMarker.java,v 1.14 2005/06/26 16:20:23 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -36,16 +36,29 @@ public class InterfaceUsageMarker
   implements ClassFileVisitor,
              CpInfoVisitor
 {
+    private UsageMarker usageMarker;
+
     // A field acting as a return parameter for several methods.
     private boolean used;
 
 
+    /**
+     * Creates a new InterfaceUsageMarker.
+     * @param usageMarker the usage marker that is used to mark the classes
+     *                    and class members.
+     */
+    public InterfaceUsageMarker(UsageMarker usageMarker)
+    {
+        this.usageMarker = usageMarker;
+    }
+
+
     // Implementations for ClassFileVisitor.
 
     public void visitProgramClassFile(ProgramClassFile programClassFile)
     {
-        boolean classUsed         = UsageMarker.isUsed(programClassFile);
-        boolean classPossiblyUsed = UsageMarker.isPossiblyUsed(programClassFile);
+        boolean classUsed         = usageMarker.isUsed(programClassFile);
+        boolean classPossiblyUsed = usageMarker.isPossiblyUsed(programClassFile);
 
         if (classUsed || classPossiblyUsed)
         {
@@ -61,12 +74,12 @@ public class InterfaceUsageMarker
             // Is this an interface with a preliminary mark?
             if (classPossiblyUsed)
             {
-                // Should it now be included?
+                // Should it be included now?
                 if (classUsed)
                 {
                     // At least one if this interface's interfaces is being used.
                     // Mark this interface as well.
-                    UsageMarker.markAsUsed(programClassFile);
+                    usageMarker.markAsUsed(programClassFile);
 
                     // Mark this interface's name.
                     markCpEntry(programClassFile, programClassFile.u2thisClass);
@@ -80,7 +93,7 @@ public class InterfaceUsageMarker
                 else
                 {
                     // Unmark this interface, so we don't bother looking at it again.
-                    UsageMarker.markAsUnused(programClassFile);
+                    usageMarker.markAsUnused(programClassFile);
                 }
             }
         }
@@ -112,7 +125,7 @@ public class InterfaceUsageMarker
 
     public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
     {
-        boolean classUsed = UsageMarker.isUsed(classCpInfo);
+        boolean classUsed = usageMarker.isUsed(classCpInfo);
 
         if (!classUsed)
         {
@@ -125,7 +138,7 @@ public class InterfaceUsageMarker
             {
                 // The class is being used. Mark the ClassCpInfo as being used
                 // as well.
-                UsageMarker.markAsUsed(classCpInfo);
+                usageMarker.markAsUsed(classCpInfo);
 
                 markCpEntry(classFile, classCpInfo.u2nameIndex);
             }
@@ -138,9 +151,9 @@ public class InterfaceUsageMarker
 
     public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo)
     {
-        if (!UsageMarker.isUsed(utf8CpInfo))
+        if (!usageMarker.isUsed(utf8CpInfo))
         {
-            UsageMarker.markAsUsed(utf8CpInfo);
+            usageMarker.markAsUsed(utf8CpInfo);
         }
     }
 
diff --git a/src/proguard/shrink/ShortestUsageMark.java b/src/proguard/shrink/ShortestUsageMark.java
new file mode 100644
index 0000000..f179ddc
--- /dev/null
+++ b/src/proguard/shrink/ShortestUsageMark.java
@@ -0,0 +1,183 @@
+/* $Id: ShortestUsageMark.java,v 1.4 2005/06/11 13:21:35 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.shrink;
+
+import proguard.classfile.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This class can be used as a mark when keeping classes, class members, and
+ * other elements. It can be certain or preliminary. It also contains additional
+ * information about the reasons why an element is being kept.
+ *
+ * @see ClassFileShrinker
+ *
+ * @author Eric Lafortune
+ */
+class ShortestUsageMark
+{
+    private boolean    certain;
+    private String     reason;
+    private int        depth;
+    private ClassFile  classFile;
+    private MethodInfo methodInfo;
+
+
+    /**
+     * Creates a new certain ShortestUsageMark.
+     * @param reason the reason for this mark.
+     */
+    public ShortestUsageMark(String reason)
+    {
+        this.certain = true;
+        this.reason  = reason;
+        this.depth   = 0;
+    }
+
+
+    /**
+     * Creates a new certain ShortestUsageMark.
+     * @param previousUsageMark the previous mark to which this one is linked.
+     * @param reason            the reason for this mark.
+     * @param classFile         the class causing this mark.
+     */
+    public ShortestUsageMark(ShortestUsageMark previousUsageMark,
+                             String            reason,
+                             int               cost,
+                             ClassFile         classFile)
+    {
+        this(previousUsageMark, reason, cost, classFile, null);
+    }
+
+
+    /**
+     * Creates a new certain ShortestUsageMark.
+     * @param previousUsageMark the previous mark to which this one is linked.
+     * @param reason            the reason for this mark.
+     * @param classFile         the class causing this mark.
+     * @param methodInfo        the method in the above class causing this mark.
+     * @param cost              the added cost of following this path.
+     */
+    public ShortestUsageMark(ShortestUsageMark previousUsageMark,
+                             String            reason,
+                             int               cost,
+                             ClassFile         classFile,
+                             MethodInfo        methodInfo)
+    {
+        this.certain    = true;
+        this.reason     = reason;
+        this.depth      = previousUsageMark.depth + cost;
+        this.classFile  = classFile;
+        this.methodInfo = methodInfo;
+    }
+
+
+    /**
+     * Creates a new ShortestUsageMark, based on another mark.
+     * @param otherUsageMark the other mark, whose properties will be copied.
+     * @param certain        specifies whether this is a certain mark.
+     */
+    public ShortestUsageMark(ShortestUsageMark otherUsageMark,
+                             boolean           certain)
+    {
+        this.certain    = certain;
+        this.reason     = otherUsageMark.reason;
+        this.depth      = otherUsageMark.depth;
+        this.classFile  = otherUsageMark.classFile;
+        this.methodInfo = otherUsageMark.methodInfo;
+    }
+
+
+    /**
+     * Returns whether this is a certain mark.
+     */
+    public boolean isCertain()
+    {
+        return certain;
+    }
+
+
+    /**
+     * Returns the reason for this mark.
+     */
+    public String getReason()
+    {
+        return reason;
+    }
+
+
+    /**
+     * Returns whether this mark has a shorter chain of reasons than the
+     * given mark.
+     */
+    public boolean isShorter(ShortestUsageMark otherUsageMark)
+    {
+        return this.depth < otherUsageMark.depth;
+    }
+
+
+    /**
+     * Returns whether this is mark is caused by the given class file.
+     */
+    public boolean isCausedBy(ClassFile classFile)
+    {
+        return classFile.equals(this.classFile);
+    }
+
+
+    /**
+     * Applies the given class file visitor to this mark's class, if any,
+     * and if this mark doesn't have a method.
+     */
+    public void acceptClassFileVisitor(ClassFileVisitor classFileVisitor)
+    {
+        if (classFile  != null &&
+            methodInfo == null)
+        {
+            classFile.accept(classFileVisitor);
+        }
+    }
+
+
+    /**
+     * Applies the given class file visitor to this mark's method, if any.
+     */
+    public void acceptMethodInfoVisitor(MemberInfoVisitor memberInfoVisitor)
+    {
+        if (classFile  != null &&
+            methodInfo != null)
+        {
+            methodInfo.accept(classFile, memberInfoVisitor);
+        }
+    }
+
+
+    // Implementations for Object.
+
+    public String toString()
+    {
+        return "certain=" + certain + ", depth="+depth+": " +
+               reason +
+               (classFile  != null ? classFile.getName() : "(none)") + ": " +
+               (methodInfo != null ? methodInfo.getName(classFile) : "(none)");
+    }
+}
diff --git a/src/proguard/shrink/ShortestUsageMarker.java b/src/proguard/shrink/ShortestUsageMarker.java
new file mode 100644
index 0000000..0cd94a1
--- /dev/null
+++ b/src/proguard/shrink/ShortestUsageMarker.java
@@ -0,0 +1,264 @@
+/* $Id: ShortestUsageMarker.java,v 1.3 2005/06/11 13:13:16 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.shrink;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+import proguard.classfile.instruction.*;
+import proguard.classfile.visitor.*;
+
+
+/**
+ * This ClassFileVisitor and MemberInfoVisitor recursively marks all classes
+ * and class elements that are being used. For each element, it finds the
+ * shortest chain of dependencies.
+ *
+ * @see ClassFileShrinker
+ *
+ * @author Eric Lafortune
+ */
+public class ShortestUsageMarker extends UsageMarker
+{
+    private static final ShortestUsageMark INITIAL_MARK =
+        new ShortestUsageMark("is kept by a directive in the configuration.\n\n");
+
+
+    // A field acting as a parameter to the visitor methods.
+    private ShortestUsageMark currentUsageMark = INITIAL_MARK;
+
+    // A utility object to check for recursive causes.
+    private MyRecursiveCauseChecker recursiveCauseChecker = new MyRecursiveCauseChecker();
+
+
+    // Overriding implementations for UsageMarker.
+
+    protected void markProgramClassBody(ProgramClassFile programClassFile)
+    {
+        ShortestUsageMark previousUsageMark = currentUsageMark;
+
+        currentUsageMark = new ShortestUsageMark(getShortestUsageMark(programClassFile),
+                                                 "is extended by ",
+                                                 10000,
+                                                 programClassFile);
+
+        super.markProgramClassBody(programClassFile);
+
+        currentUsageMark = previousUsageMark;
+    }
+
+
+    protected void markProgramMethodBody(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+    {
+        ShortestUsageMark previousUsageMark = currentUsageMark;
+
+        currentUsageMark = new ShortestUsageMark(getShortestUsageMark(programMethodInfo),
+                                                 "is invoked by  ",
+                                                 1,
+                                                 programClassFile,
+                                                 programMethodInfo);
+
+        super.markProgramMethodBody(programClassFile, programMethodInfo);
+
+        currentUsageMark = previousUsageMark;
+    }
+
+
+    protected void markMethodHierarchy(ClassFile classFile, MethodInfo methodInfo)
+    {
+        ShortestUsageMark previousUsageMark = currentUsageMark;
+
+        currentUsageMark = new ShortestUsageMark(getShortestUsageMark(methodInfo),
+                                                 "implements     ",
+                                                 100,
+                                                 classFile,
+                                                 methodInfo);
+
+        super.markMethodHierarchy(classFile, methodInfo);
+
+        currentUsageMark = previousUsageMark;
+    }
+
+
+    // Small utility methods.
+
+    protected void markAsUsed(VisitorAccepter visitorAccepter)
+    {
+        Object visitorInfo = visitorAccepter.getVisitorInfo();
+
+        ShortestUsageMark shortestUsageMark =
+            visitorInfo != null                           &&
+            visitorInfo instanceof ShortestUsageMark      &&
+            !((ShortestUsageMark)visitorInfo).isCertain() &&
+            !currentUsageMark.isShorter((ShortestUsageMark)visitorInfo) ?
+                new ShortestUsageMark((ShortestUsageMark)visitorInfo, true):
+                currentUsageMark;
+
+        visitorAccepter.setVisitorInfo(shortestUsageMark);
+    }
+
+
+    protected boolean shouldBeMarkedAsUsed(VisitorAccepter visitorAccepter)
+    {
+        Object visitorInfo = visitorAccepter.getVisitorInfo();
+
+        return //!(visitorAccepter instanceof ClassFile &&
+               //  isCausedBy(currentUsageMark, (ClassFile)visitorAccepter)) &&
+               (visitorInfo == null                           ||
+               !(visitorInfo instanceof ShortestUsageMark)   ||
+               !((ShortestUsageMark)visitorInfo).isCertain() ||
+               currentUsageMark.isShorter((ShortestUsageMark)visitorInfo));
+    }
+
+
+    protected boolean isUsed(VisitorAccepter visitorAccepter)
+    {
+        Object visitorInfo = visitorAccepter.getVisitorInfo();
+
+        return visitorInfo != null                      &&
+               visitorInfo instanceof ShortestUsageMark &&
+               ((ShortestUsageMark)visitorInfo).isCertain();
+    }
+
+
+    protected void markAsPossiblyUsed(VisitorAccepter visitorAccepter)
+    {
+        visitorAccepter.setVisitorInfo(new ShortestUsageMark(currentUsageMark, false));
+    }
+
+
+    protected boolean shouldBeMarkedAsPossiblyUsed(VisitorAccepter visitorAccepter)
+    {
+        Object visitorInfo = visitorAccepter.getVisitorInfo();
+
+        return visitorInfo == null                         ||
+               !(visitorInfo instanceof ShortestUsageMark) ||
+               (!((ShortestUsageMark)visitorInfo).isCertain() &&
+                currentUsageMark.isShorter((ShortestUsageMark)visitorInfo));
+    }
+
+
+    protected boolean isPossiblyUsed(VisitorAccepter visitorAccepter)
+    {
+        Object visitorInfo = visitorAccepter.getVisitorInfo();
+
+        return visitorInfo != null                      &&
+               visitorInfo instanceof ShortestUsageMark &&
+               !((ShortestUsageMark)visitorInfo).isCertain();
+    }
+
+
+    protected ShortestUsageMark getShortestUsageMark(VisitorAccepter visitorAccepter)
+    {
+        Object visitorInfo = visitorAccepter.getVisitorInfo();
+
+        return (ShortestUsageMark)visitorInfo;
+    }
+
+
+    // Small utility methods.
+
+    private boolean isCausedBy(ShortestUsageMark shortestUsageMark,
+                               ClassFile         classFile)
+    {
+        return recursiveCauseChecker.check(shortestUsageMark, classFile);
+    }
+
+
+    private class MyRecursiveCauseChecker implements ClassFileVisitor, MemberInfoVisitor
+    {
+        private ClassFile checkClassFile;
+        private boolean   isRecursing;
+
+
+        public boolean check(ShortestUsageMark shortestUsageMark,
+                             ClassFile         classFile)
+        {
+            checkClassFile = classFile;
+            isRecursing    = false;
+
+            shortestUsageMark.acceptClassFileVisitor(this);
+            shortestUsageMark.acceptMethodInfoVisitor(this);
+
+            return isRecursing;
+        }
+
+        // Implementations for ClassFileVisitor.
+
+        public void visitProgramClassFile(ProgramClassFile programClassFile)
+        {
+            checkCause(programClassFile);
+        }
+
+
+        public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+        {
+            checkCause(libraryClassFile);
+        }
+
+
+        // Implementations for MemberInfoVisitor.
+
+        public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+        {
+            checkCause(programFieldInfo);
+        }
+
+
+        public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+        {
+            checkCause(programMethodInfo);
+        }
+
+
+        public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+        {
+             checkCause(libraryFieldInfo);
+       }
+
+
+        public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+        {
+            checkCause(libraryMethodInfo);
+        }
+
+
+        // Small utility methods.
+
+        private void checkCause(VisitorAccepter visitorAccepter)
+        {
+            if (ShortestUsageMarker.this.isUsed(visitorAccepter))
+            {
+                ShortestUsageMark shortestUsageMark = ShortestUsageMarker.this.getShortestUsageMark(visitorAccepter);
+
+                // Check the class of this mark, if any
+                isRecursing = shortestUsageMark.isCausedBy(checkClassFile);
+
+                // Check the causing class or method, if still necessary.
+                if (!isRecursing)
+                {
+                    shortestUsageMark.acceptClassFileVisitor(this);
+                    shortestUsageMark.acceptMethodInfoVisitor(this);
+                }
+            }
+        }
+    }
+}
diff --git a/src/proguard/shrink/ShortestUsagePrinter.java b/src/proguard/shrink/ShortestUsagePrinter.java
new file mode 100644
index 0000000..b92dcb8
--- /dev/null
+++ b/src/proguard/shrink/ShortestUsagePrinter.java
@@ -0,0 +1,210 @@
+/* $Id: ShortestUsagePrinter.java,v 1.3 2005/06/11 13:21:35 eric Exp $
+ *
+ * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
+ *
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.shrink;
+
+import proguard.classfile.*;
+import proguard.classfile.util.*;
+import proguard.classfile.visitor.*;
+
+import java.io.*;
+
+
+/**
+ * This ClassFileVisitor and MemberInfoVisitor prints out the reasons why
+ * class files and class members have been marked as being used.
+ *
+ * @see UsageMarker
+ *
+ * @author Eric Lafortune
+ */
+public class ShortestUsagePrinter
+  implements ClassFileVisitor,
+             MemberInfoVisitor
+{
+    private ShortestUsageMarker shortestUsageMarker;
+    private boolean             verbose;
+    private PrintStream         ps;
+
+
+    /**
+     * Creates a new UsagePrinter that prints verbosely to <code>System.out</code>.
+     * @param shortestUsageMarker the usage marker that was used to mark the
+     *                            classes and class members.
+     */
+    public ShortestUsagePrinter(ShortestUsageMarker shortestUsageMarker)
+    {
+        this(shortestUsageMarker, true);
+    }
+
+
+    /**
+     * Creates a new UsagePrinter that prints to the given stream.
+     * @param shortestUsageMarker the usage marker that was used to mark the
+     *                            classes and class members.
+     * @param verbose             specifies whether the output should be verbose.
+     */
+    public ShortestUsagePrinter(ShortestUsageMarker shortestUsageMarker,
+                                boolean             verbose)
+    {
+        this(shortestUsageMarker, verbose, System.out);
+    }
+
+    /**
+     * Creates a new UsagePrinter that prints to the given stream.
+     * @param shortestUsageMarker the usage marker that was used to mark the
+     *                            classes and class members.
+     * @param verbose             specifies whether the output should be verbose.
+     * @param printStream         the stream to which to print.
+     */
+    public ShortestUsagePrinter(ShortestUsageMarker shortestUsageMarker,
+                                boolean             verbose,
+                                PrintStream         printStream)
+    {
+        this.shortestUsageMarker = shortestUsageMarker;
+        this.verbose             = verbose;
+        this.ps                  = printStream;
+    }
+
+
+    // Implementations for ClassFileVisitor.
+
+    public void visitProgramClassFile(ProgramClassFile programClassFile)
+    {
+        // Print the name of this class file.
+        ps.println(ClassUtil.externalClassName(programClassFile.getName()));
+
+        // Print the reason for keeping this class file.
+        printReason(programClassFile);
+    }
+
+
+    public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
+    {
+        // Print the name of this class file.
+        ps.println(ClassUtil.externalClassName(libraryClassFile.getName()));
+
+        // Print the reason for keeping this class file.
+        ps.println("  is a library class.\n");
+    }
+
+
+    // Implementations for MemberInfoVisitor.
+
+    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
+    {
+        // Print the name of this field.
+        String name = programFieldInfo.getName(programClassFile);
+        String type = programFieldInfo.getDescriptor(programClassFile);
+
+        ps.println(ClassUtil.externalClassName(programClassFile.getName()) +
+                   (verbose ?
+                        ": " + ClassUtil.externalFullFieldDescription(0, name, type):
+                        "."  + name) +
+                   lineNumberRange(programClassFile, programFieldInfo));
+
+        // Print the reason for keeping this method.
+        printReason(programFieldInfo);
+    }
+
+
+    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+    {
+        // Print the name of this method.
+        String name = programMethodInfo.getName(programClassFile);
+        String type = programMethodInfo.getDescriptor(programClassFile);
+
+        ps.println(ClassUtil.externalClassName(programClassFile.getName()) +
+                   (verbose ?
+                        ": " + ClassUtil.externalFullMethodDescription(programClassFile.getName(), 0, name, type):
+                        "."  + name) +
+                   lineNumberRange(programClassFile, programMethodInfo));
+
+        // Print the reason for keeping this method.
+        printReason(programMethodInfo);
+    }
+
+
+    public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo)
+    {
+        // Print the name of this field.
+        String name = libraryFieldInfo.getName(libraryClassFile);
+        String type = libraryFieldInfo.getDescriptor(libraryClassFile);
+
+        ps.println(ClassUtil.externalClassName(libraryClassFile.getName()) +
+                   (verbose ?
+                        ": " + ClassUtil.externalFullFieldDescription(0, name, type):
+                        "."  + name));
+
+        // Print the reason for keeping this field.
+        ps.println("  is a library field.\n");
+    }
+
+
+    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
+    {
+        // Print the name of this method.
+        String name = libraryMethodInfo.getName(libraryClassFile);
+        String type = libraryMethodInfo.getDescriptor(libraryClassFile);
+
+        ps.println(ClassUtil.externalClassName(libraryClassFile.getName()) +
+                   (verbose ?
+                        ": " + ClassUtil.externalFullMethodDescription(libraryClassFile.getName(), 0, name, type):
+                        "."  + name));
+
+        // Print the reason for keeping this method.
+        ps.println("  is a library method.\n");
+    }
+
+
+    // Small utility methods.
+
+    private void printReason(VisitorAccepter visitorAccepter)
+    {
+        if (shortestUsageMarker.isUsed(visitorAccepter))
+        {
+            ShortestUsageMark shortestUsageMark = shortestUsageMarker.getShortestUsageMark(visitorAccepter);
+
+            // Print the reason for keeping this class file.
+            ps.print("  " + shortestUsageMark.getReason());
+
+            // Print the class or method that is responsible, with its reasons.
+            shortestUsageMark.acceptClassFileVisitor(this);
+            shortestUsageMark.acceptMethodInfoVisitor(this);
+        }
+        else
+        {
+            ps.println("  is not being kept.\n");
+        }
+    }
+
+
+    /**
+     * Returns the line number range of the given class member, followed by a
+     * colon, or just an empty String if no range is available.
+     */
+    private static String lineNumberRange(ProgramClassFile programClassFile, ProgramMemberInfo programMemberInfo)
+    {
+        String range = programMemberInfo.getLineNumberRange(programClassFile);
+        return range != null ?
+            (" (" + range + ")") :
+            "";
+    }
+}
diff --git a/src/proguard/shrink/UsageMarker.java b/src/proguard/shrink/UsageMarker.java
index 851f111..cbad551 100644
--- a/src/proguard/shrink/UsageMarker.java
+++ b/src/proguard/shrink/UsageMarker.java
@@ -1,8 +1,8 @@
-/* $Id: UsageMarker.java,v 1.37 2004/12/19 21:03:54 eric Exp $
+/* $Id: UsageMarker.java,v 1.46 2005/06/26 16:19:24 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -55,7 +55,8 @@ public class UsageMarker
     private static final Object USED          = new Object();
 
 
-    private MyInterfaceUsageMarker interfaceUsageMarker = new MyInterfaceUsageMarker();
+    private MyInterfaceUsageMarker          interfaceUsageMarker          = new MyInterfaceUsageMarker();
+    private MyPossiblyUsedMethodUsageMarker possiblyUsedMethodUsageMarker = new MyPossiblyUsedMethodUsageMarker();
 //    private ClassFileVisitor       dynamicClassMarker   =
 //        new MultiClassFileVisitor(
 //        new ClassFileVisitor[]
@@ -66,57 +67,57 @@ public class UsageMarker
 //                                   this)
 //        });
 
-    
-    // A field acting as a parameter to the visitMemberInfo method.
-    private boolean processing = false;
-
 
     // Implementations for ClassFileVisitor.
 
     public void visitProgramClassFile(ProgramClassFile programClassFile)
     {
-        if (!isUsed(programClassFile))
+        if (shouldBeMarkedAsUsed(programClassFile))
         {
             // Mark this class.
             markAsUsed(programClassFile);
 
-            // Mark this class's name.
-            markCpEntry(programClassFile, programClassFile.u2thisClass);
+            markProgramClassBody(programClassFile);
+        }
+    }
 
-            // Mark the superclass.
-            if (programClassFile.u2superClass != 0)
-            {
-                markCpEntry(programClassFile, programClassFile.u2superClass);
-            }
 
-            // Give the interfaces preliminary marks.
-            programClassFile.hierarchyAccept(false, false, true, false,
-                                             interfaceUsageMarker);
+    protected void markProgramClassBody(ProgramClassFile programClassFile)
+    {
+        // Mark this class's name.
+        markCpEntry(programClassFile, programClassFile.u2thisClass);
 
-            // Explicitly mark the <clinit> method.
-            programClassFile.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_CLINIT,
-                                          ClassConstants.INTERNAL_METHOD_TYPE_CLINIT,
-                                          this);
+        // Mark the superclass.
+        if (programClassFile.u2superClass != 0)
+        {
+            markCpEntry(programClassFile, programClassFile.u2superClass);
+        }
 
-            // Explicitly mark the parameterless <init> method.
-            programClassFile.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_INIT,
-                                          ClassConstants.INTERNAL_METHOD_TYPE_INIT,
-                                          this);
+        // Give the interfaces preliminary marks.
+        programClassFile.hierarchyAccept(false, false, true, false,
+                                         interfaceUsageMarker);
 
-            // Process all methods that have already been marked as possibly used.
-            processing = true;
-            programClassFile.methodsAccept(this);
-            processing = false;
+        // Explicitly mark the <clinit> method.
+        programClassFile.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_CLINIT,
+                                      ClassConstants.INTERNAL_METHOD_TYPE_CLINIT,
+                                      this);
 
-            // Mark the attributes.
-            programClassFile.attributesAccept(this);
-        }
+        // Explicitly mark the parameterless <init> method.
+        programClassFile.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_INIT,
+                                      ClassConstants.INTERNAL_METHOD_TYPE_INIT,
+                                      this);
+
+        // Process all methods that have already been marked as possibly used.
+        programClassFile.methodsAccept(possiblyUsedMethodUsageMarker);
+
+        // Mark the attributes.
+        programClassFile.attributesAccept(this);
     }
 
 
     public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
     {
-        if (!isUsed(libraryClassFile))
+        if (shouldBeMarkedAsUsed(libraryClassFile))
         {
             markAsUsed(libraryClassFile);
 
@@ -158,7 +159,7 @@ public class UsageMarker
     {
         public void visitProgramClassFile(ProgramClassFile programClassFile)
         {
-            if (!isUsed(programClassFile))
+            if (shouldBeMarkedAsPossiblyUsed(programClassFile))
             {
                 // We can't process the interface yet, because it might not
                 // be required. Give it a preliminary mark.
@@ -174,11 +175,39 @@ public class UsageMarker
     }
 
 
+    private class MyPossiblyUsedMethodUsageMarker implements MemberInfoVisitor
+    {
+        // Implementations for MemberInfoVisitor.
+    
+        public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
+    
+    
+        public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
+        {
+            // Has the method already been referenced?
+            if (isPossiblyUsed(programMethodInfo))
+            {
+                markAsUsed(programMethodInfo);
+
+                // Mark the method body.
+                markProgramMethodBody(programClassFile, programMethodInfo);
+                
+                // Note that, if the method has been marked as possibly used,
+                // the method hierarchy has already been marked (cfr. below).
+            }
+        }
+    
+    
+        public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
+        public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
+    }
+
+    
     // Implementations for MemberInfoVisitor.
 
     public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
     {
-        if (!isUsed(programFieldInfo))
+        if (shouldBeMarkedAsUsed(programFieldInfo))
         {
             markAsUsed(programFieldInfo);
 
@@ -197,45 +226,28 @@ public class UsageMarker
 
     public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
-        if (!isUsed(programMethodInfo))
+        if (shouldBeMarkedAsUsed(programMethodInfo))
         {
-            // Are the method and its class used?
-            if (processing ? isPossiblyUsed(programMethodInfo) :
-                             isUsed(programClassFile))
+            // Is the method's class used?
+            if (isUsed(programClassFile))
             {
                 markAsUsed(programMethodInfo);
 
-                // Remember the processing flag.
-                boolean oldProcessing = processing;
-                processing = false;
+                // Mark the method body.
+                markProgramMethodBody(programClassFile, programMethodInfo);
 
-                // Mark the name and descriptor.
-                markCpEntry(programClassFile, programMethodInfo.u2nameIndex);
-                markCpEntry(programClassFile, programMethodInfo.u2descriptorIndex);
-
-                // Mark the attributes.
-                programMethodInfo.attributesAccept(programClassFile, this);
-
-                // Mark the classes referenced in the descriptor string.
-                programMethodInfo.referencedClassesAccept(this);
-
-                // Restore the processing flag.
-                processing = oldProcessing;
-
-                // If the method is being called, mark its hierarchy.
-                if (!processing)
-                {
-                    markMethodHierarchy(programClassFile, programMethodInfo);
-                }
+                // Mark the method hierarchy.
+                markMethodHierarchy(programClassFile, programMethodInfo);
             }
-            else if (!processing && !isPossiblyUsed(programMethodInfo))
+            
+            // Hasn't the method been marked as possibly being used yet?
+            else if (shouldBeMarkedAsPossiblyUsed(programMethodInfo))
             {
-                // We can't process the class member yet, because the class
-                // file isn't marked as being used (yet). Give it a
-                // preliminary mark.
+                // We can't process the method yet, because the class isn't
+                // marked as being used (yet). Give it a preliminary mark.
                 markAsPossiblyUsed(programMethodInfo);
 
-                // The method is being called. Mark its hierarchy.
+                // Mark the method hierarchy.
                 markMethodHierarchy(programClassFile, programMethodInfo);
             }
         }
@@ -246,58 +258,37 @@ public class UsageMarker
 
     public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
     {
-        if (!isUsed(libraryMethodInfo))
+        if (shouldBeMarkedAsUsed(libraryMethodInfo))
         {
             markAsUsed(libraryMethodInfo);
-            
+
+            // Mark the method hierarchy.
             markMethodHierarchy(libraryClassFile, libraryMethodInfo);
         }
     }
 
 
-    private void markMethodHierarchy(ClassFile classFile, MethodInfo methodInfo)
+    protected void markProgramMethodBody(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
-        if ((methodInfo.getAccessFlags() &
-             (ClassConstants.INTERNAL_ACC_PRIVATE |
-              ClassConstants.INTERNAL_ACC_FINAL)) == 0)
-        {
-            String name = methodInfo.getName(classFile);
-            String type = methodInfo.getDescriptor(classFile);
+        // Mark the name and descriptor.
+        markCpEntry(programClassFile, programMethodInfo.u2nameIndex);
+        markCpEntry(programClassFile, programMethodInfo.u2descriptorIndex);
 
-            if (!name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) &&
-                !name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT))
-            {
-                // Mark all implementations of the method.
-                //
-                // For an abstract method:
-                //   First go to all concrete implementations or extensions of
-                //   the interface or abstract class.
-                //   From there, travel up and down the class hierarchy to mark
-                //   the method.
-                //
-                //   This way, we're also catching retro-fitted interfaces,
-                //   where a class's implementation of an interface method is
-                //   hiding higher up its class hierarchy.
-                //
-                // For a concrete method:
-                //   Simply mark all overriding implementations down the
-                //   class hierarchy.
-                classFile.accept(
-                    (classFile.getAccessFlags()  & ClassConstants.INTERNAL_ACC_INTERFACE) != 0 ||
-                    (methodInfo.getAccessFlags() & ClassConstants.INTERNAL_ACC_ABSTRACT)  != 0 ?
-    
-                        (ClassFileVisitor)
-                        new ConcreteClassFileDownTraveler(
-                        new ClassFileHierarchyTraveler(true, true, false, true,
-                        new NamedMethodVisitor(name, type,
-                        new MemberInfoAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, this)))) :
-    
-                        (ClassFileVisitor)
-                        new ClassFileHierarchyTraveler(false, false, false, true,
-                        new NamedMethodVisitor(name, type,
-                        new MemberInfoAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, this))));
-            }
-        }
+        // Mark the attributes.
+        programMethodInfo.attributesAccept(programClassFile, this);
+
+        // Mark the classes referenced in the descriptor string.
+        programMethodInfo.referencedClassesAccept(this);
+    }
+
+
+    /**
+     * Marks the hierarchy of implementing or overriding methods corresponding
+     * to the given method, if any.
+     */
+    protected void markMethodHierarchy(ClassFile classFile, MethodInfo methodInfo)
+    {
+        classFile.methodImplementationsAccept(methodInfo, false, this);
     }
 
 
@@ -305,7 +296,7 @@ public class UsageMarker
 
     public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo)
     {
-        if (!isUsed(integerCpInfo))
+        if (shouldBeMarkedAsUsed(integerCpInfo))
         {
             markAsUsed(integerCpInfo);
         }
@@ -314,7 +305,7 @@ public class UsageMarker
 
     public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo)
     {
-        if (!isUsed(longCpInfo))
+        if (shouldBeMarkedAsUsed(longCpInfo))
         {
             markAsUsed(longCpInfo);
         }
@@ -323,7 +314,7 @@ public class UsageMarker
 
     public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo)
     {
-        if (!isUsed(floatCpInfo))
+        if (shouldBeMarkedAsUsed(floatCpInfo))
         {
             markAsUsed(floatCpInfo);
         }
@@ -332,7 +323,7 @@ public class UsageMarker
 
     public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo)
     {
-        if (!isUsed(doubleCpInfo))
+        if (shouldBeMarkedAsUsed(doubleCpInfo))
         {
             markAsUsed(doubleCpInfo);
         }
@@ -341,7 +332,7 @@ public class UsageMarker
 
     public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
     {
-        if (!isUsed(stringCpInfo))
+        if (shouldBeMarkedAsUsed(stringCpInfo))
         {
             markAsUsed(stringCpInfo);
 
@@ -359,7 +350,7 @@ public class UsageMarker
 
     public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo)
     {
-        if (!isUsed(utf8CpInfo))
+        if (shouldBeMarkedAsUsed(utf8CpInfo))
         {
             markAsUsed(utf8CpInfo);
         }
@@ -386,7 +377,7 @@ public class UsageMarker
 
     private void visitRefCpInfo(ClassFile classFile, RefCpInfo methodrefCpInfo)
     {
-        if (!isUsed(methodrefCpInfo))
+        if (shouldBeMarkedAsUsed(methodrefCpInfo))
         {
             markAsUsed(methodrefCpInfo);
 
@@ -407,7 +398,7 @@ public class UsageMarker
 
     public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
     {
-        if (!isUsed(classCpInfo))
+        if (shouldBeMarkedAsUsed(classCpInfo))
         {
             markAsUsed(classCpInfo);
 
@@ -421,15 +412,12 @@ public class UsageMarker
 
     public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
     {
-        if (!isUsed(nameAndTypeCpInfo))
+        if (shouldBeMarkedAsUsed(nameAndTypeCpInfo))
         {
             markAsUsed(nameAndTypeCpInfo);
 
             markCpEntry(classFile, nameAndTypeCpInfo.u2nameIndex);
             markCpEntry(classFile, nameAndTypeCpInfo.u2descriptorIndex);
-
-            // Mark the classes referenced in the descriptor string.
-            nameAndTypeCpInfo.referencedClassesAccept(this);
         }
     }
 
@@ -451,7 +439,7 @@ public class UsageMarker
     {
         // Don't mark the attribute and its name yet. We may mark it later, in
         // InnerUsageMarker.
-        //markAsUsed(innerClassesAttrInfo);
+        //_markAsUsed(innerClassesAttrInfo);
 
         //markCpEntry(classFile, innerClassesAttrInfo.u2attrNameIndex);
         innerClassesAttrInfo.innerClassEntriesAccept(classFile, this);
@@ -784,41 +772,78 @@ public class UsageMarker
     // Small utility methods.
 
     /**
-     * Marks the given constant pool entry of the given class. This includes
-     * visiting any referenced objects.
+     * Marks the given visitor accepter as being used.
      */
-    private void markCpEntry(ClassFile classFile, int index)
+    protected void markAsUsed(VisitorAccepter visitorAccepter)
     {
-         classFile.constantPoolEntryAccept(index, this);
+        visitorAccepter.setVisitorInfo(USED);
     }
 
 
-    static void markAsUnused(VisitorAccepter visitorAccepter)
+    /**
+     * Returns whether the given visitor accepter should still be marked as
+     * being used.
+     */
+    protected boolean shouldBeMarkedAsUsed(VisitorAccepter visitorAccepter)
     {
-        visitorAccepter.setVisitorInfo(null);
+        return visitorAccepter.getVisitorInfo() != USED;
     }
 
 
-    static void markAsPossiblyUsed(VisitorAccepter visitorAccepter)
+    /**
+     * Returns whether the given visitor accepter has been marked as being used.
+     */
+    protected boolean isUsed(VisitorAccepter visitorAccepter)
+    {
+        return visitorAccepter.getVisitorInfo() == USED;
+    }
+
+
+    /**
+     * Marks the given visitor accepter as possibly being used.
+     */
+    protected void markAsPossiblyUsed(VisitorAccepter visitorAccepter)
     {
         visitorAccepter.setVisitorInfo(POSSIBLY_USED);
     }
 
 
-    static boolean isPossiblyUsed(VisitorAccepter visitorAccepter)
+    /**
+     * Returns whether the given visitor accepter should still be marked as
+     * possibly being used.
+     */
+    protected boolean shouldBeMarkedAsPossiblyUsed(VisitorAccepter visitorAccepter)
+    {
+        return visitorAccepter.getVisitorInfo() != USED &&
+               visitorAccepter.getVisitorInfo() != POSSIBLY_USED;
+    }
+
+
+    /**
+     * Returns whether the given visitor accepter has been marked as possibly
+     * being used.
+     */
+    protected boolean isPossiblyUsed(VisitorAccepter visitorAccepter)
     {
         return visitorAccepter.getVisitorInfo() == POSSIBLY_USED;
     }
 
 
-    static void markAsUsed(VisitorAccepter visitorAccepter)
+    /**
+     * Clears any usage marks from the given visitor accepter.
+     */
+    protected void markAsUnused(VisitorAccepter visitorAccepter)
     {
-        visitorAccepter.setVisitorInfo(USED);
+        visitorAccepter.setVisitorInfo(null);
     }
 
 
-    static boolean isUsed(VisitorAccepter visitorAccepter)
+    /**
+     * Marks the given constant pool entry of the given class. This includes
+     * visiting any referenced objects.
+     */
+    private void markCpEntry(ClassFile classFile, int index)
     {
-        return visitorAccepter.getVisitorInfo() == USED;
+         classFile.constantPoolEntryAccept(index, this);
     }
 }
diff --git a/src/proguard/shrink/UsagePrinter.java b/src/proguard/shrink/UsagePrinter.java
index 18abcaa..39a7c38 100644
--- a/src/proguard/shrink/UsagePrinter.java
+++ b/src/proguard/shrink/UsagePrinter.java
@@ -1,8 +1,8 @@
-/* $Id: UsagePrinter.java,v 1.16 2004/08/15 12:39:30 eric Exp $
+/* $Id: UsagePrinter.java,v 1.19 2005/06/11 13:21:35 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -39,6 +39,7 @@ public class UsagePrinter
   implements ClassFileVisitor,
              MemberInfoVisitor
 {
+    private UsageMarker usageMarker;
     private boolean     printUnusedItems;
     private PrintStream ps;
 
@@ -48,23 +49,31 @@ public class UsagePrinter
 
     /**
      * Creates a new UsagePrinter that prints to <code>System.out</code>.
+     * @param usageMarker    the usage marker that was used to mark the classes
+     *                       and class members.
      * @param printUsedItems a flag that indicates whether only unused items
-     * should be printed, or alternatively, only used items.
+     *                       should be printed, or alternatively, only used items.
      */
-    public UsagePrinter(boolean printUnusedItems)
+    public UsagePrinter(UsageMarker usageMarker,
+                        boolean     printUnusedItems)
     {
-        this(printUnusedItems, System.out);
+        this(usageMarker, printUnusedItems, System.out);
     }
 
 
     /**
      * Creates a new UsagePrinter that prints to the given stream.
+     * @param usageMarker    the usage marker that was used to mark the classes
+     *                       and class members.
      * @param printUsedItems a flag that indicates whether only unused items
-     * should be printed, or alternatively, only used items.
+     *                       should be printed, or alternatively, only used items.
      * @param printStream the stream to which to print
      */
-    public UsagePrinter(boolean printUnusedItems, PrintStream printStream)
+    public UsagePrinter(UsageMarker usageMarker,
+                        boolean     printUnusedItems,
+                        PrintStream printStream)
     {
+        this.usageMarker      = usageMarker;
         this.printUnusedItems = printUnusedItems;
         this.ps               = printStream;
     }
@@ -74,7 +83,7 @@ public class UsagePrinter
 
     public void visitProgramClassFile(ProgramClassFile programClassFile)
     {
-        if (UsageMarker.isUsed(programClassFile))
+        if (usageMarker.isUsed(programClassFile))
         {
             if (printUnusedItems)
             {
@@ -109,7 +118,7 @@ public class UsagePrinter
 
     public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
     {
-        if (UsageMarker.isUsed(programFieldInfo) ^ printUnusedItems)
+        if (usageMarker.isUsed(programFieldInfo) ^ printUnusedItems)
         {
             printClassNameHeader();
 
@@ -125,7 +134,7 @@ public class UsagePrinter
 
     public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
     {
-        if (UsageMarker.isUsed(programMethodInfo) ^ printUnusedItems)
+        if (usageMarker.isUsed(programMethodInfo) ^ printUnusedItems)
         {
             printClassNameHeader();
 
diff --git a/src/proguard/shrink/UsedClassFileFilter.java b/src/proguard/shrink/UsedClassFileFilter.java
index 6b33c62..2379522 100644
--- a/src/proguard/shrink/UsedClassFileFilter.java
+++ b/src/proguard/shrink/UsedClassFileFilter.java
@@ -1,8 +1,8 @@
-/* $Id: UsedClassFileFilter.java,v 1.9 2004/08/15 12:39:30 eric Exp $
+/* $Id: UsedClassFileFilter.java,v 1.11 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -35,11 +35,21 @@ import proguard.classfile.visitor.*;
 public class UsedClassFileFilter
   implements ClassFileVisitor
 {
-    ClassFileVisitor classFileVisitor;
+    private UsageMarker      usageMarker;
+    private ClassFileVisitor classFileVisitor;
 
 
-    public UsedClassFileFilter(ClassFileVisitor classFileVisitor)
+    /**
+     * Creates a new UsedClassFileFilter.
+     * @param usageMarker      the usage marker that is used to mark the classes
+     *                         and class members.
+     * @param classFileVisitor the class file visitor to which the visiting
+     *                         will be delegated.
+     */
+    public UsedClassFileFilter(UsageMarker      usageMarker,
+                                ClassFileVisitor classFileVisitor)
     {
+        this.usageMarker      = usageMarker;
         this.classFileVisitor = classFileVisitor;
     }
 
@@ -48,7 +58,7 @@ public class UsedClassFileFilter
 
     public void visitProgramClassFile(ProgramClassFile programClassFile)
     {
-        if (UsageMarker.isUsed(programClassFile))
+        if (usageMarker.isUsed(programClassFile))
         {
             classFileVisitor.visitProgramClassFile(programClassFile);
         }
@@ -57,7 +67,7 @@ public class UsedClassFileFilter
 
     public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
     {
-        if (UsageMarker.isUsed(libraryClassFile))
+        if (usageMarker.isUsed(libraryClassFile))
         {
             classFileVisitor.visitLibraryClassFile(libraryClassFile);
         }
diff --git a/src/proguard/util/BasicMatcher.java b/src/proguard/util/BasicMatcher.java
index ee173eb..b10f3e4 100644
--- a/src/proguard/util/BasicMatcher.java
+++ b/src/proguard/util/BasicMatcher.java
@@ -1,4 +1,4 @@
-/* $Id: BasicMatcher.java,v 1.6 2004/08/15 12:39:30 eric Exp $
+/* $Id: BasicMatcher.java,v 1.7 2005/05/22 00:23:31 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
@@ -67,12 +67,12 @@ public class BasicMatcher implements StringMatcher
 
     /**
      * Creates a new BasicMatcher.
-     * @param regularExpression the regular expression against which strings
-     *                          will be matched.
-     * @param wildcardCharacters an optional extra list of wildcard matching
-     *                           characters.
-     * @param wildcardCharacters an optional extra list of extended wildcard
-     *                           matching characters.
+     * @param regularExpression          the regular expression against which
+     *                                   strings will be matched.
+     * @param wildcardCharacters         an optional extra list of wildcard
+     *                                   matching characters.
+     * @param extendedWildcardCharacters an optional extra list of extended
+     *                                   wildcard matching characters.
      */
     public BasicMatcher(String regularExpression,
                         char[] wildcardCharacters,
diff --git a/src/proguard/util/ExtensionMatcher.java b/src/proguard/util/ExtensionMatcher.java
index 84cc834..101cb1b 100644
--- a/src/proguard/util/ExtensionMatcher.java
+++ b/src/proguard/util/ExtensionMatcher.java
@@ -1,8 +1,8 @@
-/* $Id: ExtensionMatcher.java,v 1.2 2004/08/15 12:39:30 eric Exp $
+/* $Id: ExtensionMatcher.java,v 1.3 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/util/FileNameMatcher.java b/src/proguard/util/FileNameMatcher.java
index 719c71f..86c6cc2 100644
--- a/src/proguard/util/FileNameMatcher.java
+++ b/src/proguard/util/FileNameMatcher.java
@@ -1,4 +1,4 @@
-/* $Id: FileNameMatcher.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+/* $Id: FileNameMatcher.java,v 1.6 2005/04/17 15:32:36 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
@@ -41,6 +41,7 @@ public class FileNameMatcher extends BasicMatcher
     private static final char[] FILE_NAME_CHARACTERS = new char[]
     {
         ' ',
+        '-',
         '.'
     };
 
diff --git a/src/proguard/util/ListUtil.java b/src/proguard/util/ListUtil.java
index c0f7721..e324869 100644
--- a/src/proguard/util/ListUtil.java
+++ b/src/proguard/util/ListUtil.java
@@ -1,8 +1,8 @@
-/* $Id: ListUtil.java,v 1.5 2004/08/15 12:39:30 eric Exp $
+/* $Id: ListUtil.java,v 1.6 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
diff --git a/src/proguard/wtk/ProGuardObfuscator.java b/src/proguard/wtk/ProGuardObfuscator.java
index c406805..e2e01ee 100644
--- a/src/proguard/wtk/ProGuardObfuscator.java
+++ b/src/proguard/wtk/ProGuardObfuscator.java
@@ -1,8 +1,8 @@
-/* $Id: ProGuardObfuscator.java,v 1.12 2004/08/15 12:39:30 eric Exp $
+/* $Id: ProGuardObfuscator.java,v 1.15 2005/06/11 13:13:16 eric Exp $
  *
  * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
  *
- * Copyright (c) 2002-2004 Eric Lafortune (eric at graphics.cornell.edu)
+ * Copyright (c) 2002-2005 Eric Lafortune (eric at graphics.cornell.edu)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -69,13 +69,14 @@ public class ProGuardObfuscator implements Obfuscator
                     String emptyAPI)
     throws IOException
     {
+        // Create the ProGuard configuration.
+        Configuration configuration = new Configuration();
+
+        // Parse the default configuration file.
+        ConfigurationParser parser = new ConfigurationParser(this.getClass().getResource(DEFAULT_CONFIGURATION));
+
         try
         {
-            // Create the ProGuard configuration.
-            Configuration configuration = new Configuration();
-
-            // Parse the default configuration file.
-            ConfigurationParser parser = new ConfigurationParser(this.getClass().getResource(DEFAULT_CONFIGURATION));
             parser.parse(configuration);
 
             // Fill out the library class path.
@@ -83,8 +84,8 @@ public class ProGuardObfuscator implements Obfuscator
 
             // Fill out the program class path (input and output).
             configuration.programJars = new ClassPath();
-            configuration.programJars.add(new ClassPathEntry(jarFileName, false));
-            configuration.programJars.add(new ClassPathEntry(obfuscatedJarFile.getPath(), true));
+            configuration.programJars.add(new ClassPathEntry(new File(jarFileName), false));
+            configuration.programJars.add(new ClassPathEntry(obfuscatedJarFile, true));
 
             // The preverify tool seems to unpack the resulting class files,
             // so we must not use mixed-case class names on Windows.
@@ -100,6 +101,10 @@ public class ProGuardObfuscator implements Obfuscator
         {
             throw new IOException(ex.getMessage());
         }
+        finally
+        {
+            parser.close();
+        }
     }
 
 
@@ -124,7 +129,7 @@ public class ProGuardObfuscator implements Obfuscator
 
             // Create and add the found class path entry.
             ClassPathEntry classPathEntry =
-                new ClassPathEntry(classPathString.substring(index, next_index),
+                new ClassPathEntry(new File(classPathString.substring(index, next_index)),
                                    false);
 
             classPath.add(classPathEntry);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/proguard.git



More information about the pkg-java-commits mailing list