Skip to content
Commits on Source (2)
......@@ -8,7 +8,7 @@
<parent>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-parent</artifactId>
<version>6.0.1</version>
<version>6.0.3</version>
<relativePath>../buildscripts/pom.xml</relativePath>
</parent>
<artifactId>proguard-annotations</artifactId>
......
......@@ -8,7 +8,7 @@
<parent>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-parent</artifactId>
<version>6.0.1</version>
<version>6.0.3</version>
<relativePath>../buildscripts/pom.xml</relativePath>
</parent>
<artifactId>proguard-anttask</artifactId>
......
......@@ -7,7 +7,7 @@
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-parent</artifactId>
<version>6.0.1</version>
<version>6.0.3</version>
<packaging>pom</packaging>
<name>[${project.groupId}] ${project.artifactId}</name>
<description>ProGuard is a free Java class file shrinker, optimizer, obfuscator, and preverifier.</description>
......
......@@ -8,7 +8,7 @@
<parent>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-parent</artifactId>
<version>6.0.1</version>
<version>6.0.3</version>
<relativePath>../buildscripts/pom.xml</relativePath>
</parent>
<artifactId>proguard-base</artifactId>
......
......@@ -545,7 +545,7 @@ public class ClassSpecificationVisitorFactory
StringMatcher nameMatcher = name == null ? null :
new ListParser(new NameParser(variableStringMatchers)).parse(name);
StringMatcher descriptorMatcher = name == null ? null :
StringMatcher descriptorMatcher = descriptor == null ? null :
new ListParser(new ClassNameParser(variableStringMatchers)).parse(descriptor);
StringMatcher attributesMatcher = attributeNames == null ? null :
......
......@@ -95,31 +95,31 @@ public class DataEntryReaderFactory
}
// Unzip any apks, if necessary.
reader = wrapInJarReader(reader, false, isApk, apkFilter, ".apk");
reader = wrapInJarReader(reader, false, false, isApk, apkFilter, ".apk");
if (!isApk)
{
// Unzip any jars, if necessary.
reader = wrapInJarReader(reader, false, isJar, jarFilter, ".jar");
reader = wrapInJarReader(reader, false, false, isJar, jarFilter, ".jar");
if (!isJar)
{
// Unzip any aars, if necessary.
reader = wrapInJarReader(reader, false, isAar, aarFilter, ".aar");
reader = wrapInJarReader(reader, false, false, isAar, aarFilter, ".aar");
if (!isAar)
{
// Unzip any wars, if necessary.
reader = wrapInJarReader(reader, false, isWar, warFilter, ".war");
reader = wrapInJarReader(reader, true, false, isWar, warFilter, ".war");
if (!isWar)
{
// Unzip any ears, if necessary.
reader = wrapInJarReader(reader, false, isEar, earFilter, ".ear");
reader = wrapInJarReader(reader, false, false, isEar, earFilter, ".ear");
if (!isEar)
{
// Unzip any jmods, if necessary.
reader = wrapInJarReader(reader, true, isJmod, jmodFilter, ".jmod");
reader = wrapInJarReader(reader, true, true, isJmod, jmodFilter, ".jmod");
if (!isJmod)
{
// Unzip any zips, if necessary.
reader = wrapInJarReader(reader, false, isZip, zipFilter, ".zip");
reader = wrapInJarReader(reader, false, false, isZip, zipFilter, ".zip");
}
}
}
......@@ -132,12 +132,14 @@ public class DataEntryReaderFactory
/**
* Wraps the given DataEntryReader in a JarReader, filtering it if necessary.
* Wraps the given DataEntryReader in a JarReader, filtering it if
* necessary.
* @param reader the data entry reader that can read the
* entries contained in the jar file.
* @param isJmod specifies whether to strip the "classes/"
* prefix from contained .class data entries
* and the jmod magic bytes from the zip.
* @param stripClassesPrefix specifies whether to strip the ""classes/"
* prefix from contained .class data entries.
*@param stripJmodHeader specifies whether to strip the jmod magic
* bytes from the zip.
* @param isJar specifies whether the data entries should
* always be unzipped.
* @param jarFilter otherwise, an optional filter on the data
......@@ -148,21 +150,22 @@ public class DataEntryReaderFactory
* entries.
*/
private static DataEntryReader wrapInJarReader(DataEntryReader reader,
boolean isJmod,
boolean stripClassesPrefix,
boolean stripJmodHeader,
boolean isJar,
List jarFilter,
String jarExtension)
{
if (isJmod)
if (stripClassesPrefix)
{
reader = new FilteredDataEntryReader(
new DataEntryNameFilter(new ExtensionMatcher(".class")),
new PrefixStrippingDataEntryReader("classes/", reader),
new DataEntryNameFilter(new ExtensionMatcher(ClassConstants.CLASS_FILE_EXTENSION)),
new PrefixStrippingDataEntryReader(ClassConstants.JMOD_CLASS_FILE_PREFIX, reader),
reader);
}
// Unzip any jars, if necessary.
DataEntryReader jarReader = new JarReader(reader, isJmod);
DataEntryReader jarReader = new JarReader(reader, stripJmodHeader);
if (isJar)
{
......
......@@ -129,19 +129,30 @@ public class DataEntryWriterFactory
isJmod ||
isZip);
// If the output is an archive, we'll flatten (unpack the contents of)
// higher level input archives, e.g. when writing into a jar file, we
// flatten zip files.
boolean flattenApks = false;
boolean flattenJars = flattenApks || isApk;
boolean flattenAars = flattenJars || isJar;
boolean flattenWars = flattenAars || isAar;
boolean flattenEars = flattenWars || isWar;
boolean flattenJmods = flattenEars || isEar;
boolean flattenZips = flattenJmods || isJmod;
// Set up the filtered jar writers.
writer = wrapInJarWriter(writer, false, null, isZip, zipFilter, ".zip", isApk || isJar || isAar || isWar || isEar || isJmod);
writer = wrapInJarWriter(writer, true, ClassConstants.JMOD_HEADER, isJmod, jmodFilter, ".jmod", isApk || isJar || isAar || isWar || isEar);
writer = wrapInJarWriter(writer, false, null, isEar, earFilter, ".ear", isApk || isJar || isAar || isWar);
writer = wrapInJarWriter(writer, true, null, isWar, warFilter, ".war", isApk || isJar || isAar);
writer = wrapInJarWriter(writer, false, null, isAar, aarFilter, ".aar", isApk || isJar);
writer = wrapInJarWriter(writer, false, null, isJar, jarFilter, ".jar", isApk);
writer = wrapInJarWriter(writer, false, null, isApk, apkFilter, ".apk", false);
writer = wrapInJarWriter(writer, flattenZips, isZip, ".zip", zipFilter, null, null);
writer = wrapInJarWriter(writer, flattenJmods, isJmod, ".jmod", jmodFilter, ClassConstants.JMOD_HEADER, ClassConstants.JMOD_CLASS_FILE_PREFIX);
writer = wrapInJarWriter(writer, flattenEars, isEar, ".ear", earFilter, null, null);
writer = wrapInJarWriter(writer, flattenWars, isWar, ".war", warFilter, null, ClassConstants.WAR_CLASS_FILE_PREFIX);
writer = wrapInJarWriter(writer, flattenAars, isAar, ".aar", aarFilter, null, null);
writer = wrapInJarWriter(writer, flattenJars, isJar, ".jar", jarFilter, null, null);
writer = wrapInJarWriter(writer, flattenApks, isApk, ".apk", apkFilter, null, null);
// Set up for writing out the program classes.
writer = new ClassDataEntryWriter(programClassPool, writer);
// Add a filter, if specified.
// Add a data entry filter, if specified.
writer = filter != null ?
new FilteredDataEntryWriter(
new DataEntryNameFilter(
......@@ -166,46 +177,61 @@ public class DataEntryWriterFactory
* Wraps the given DataEntryWriter in a JarWriter, filtering if necessary.
*/
private DataEntryWriter wrapInJarWriter(DataEntryWriter writer,
boolean addClassesPrefix,
byte[] header,
boolean isJar,
boolean flatten,
boolean isOutputJar,
String jarFilterExtension,
List jarFilter,
String jarExtension,
boolean dontWrap)
byte[] jarHeader,
String classFilePrefix)
{
// Zip up jars, if necessary.
DataEntryWriter jarWriter =
dontWrap ?
new ParentDataEntryWriter(writer) :
new JarWriter(header, writer);
// Add a "classes/" prefix for class files, if specified.
if (addClassesPrefix)
// Flatten jars or zip them up.
DataEntryWriter jarWriter;
if (flatten)
{
writer = new FilteredDataEntryWriter(
new DataEntryNameFilter(
new ExtensionMatcher(".class")),
new PrefixAddingDataEntryWriter("classes/",
writer),
writer);
// Unpack the jar.
jarWriter = new ParentDataEntryWriter(writer);
}
else
{
// Pack the jar.
jarWriter = new JarWriter(jarHeader, writer);
// Add a prefix for class files inside the jar, if specified.
if (classFilePrefix != null)
{
jarWriter =
new FilteredDataEntryWriter(
new DataEntryNameFilter(
new ExtensionMatcher(ClassConstants.CLASS_FILE_EXTENSION)),
new PrefixAddingDataEntryWriter(classFilePrefix,
jarWriter),
jarWriter);
}
}
// Add a filter, if specified.
DataEntryWriter filteredJarWriter = jarFilter != null ?
// Either zip up the jar or delegate to the original writer.
return
new FilteredDataEntryWriter(
new DataEntryParentFilter(
new DataEntryNameFilter(
new ListParser(new FileNameParser()).parse(jarFilter))),
jarWriter) :
jarWriter;
// Only zip up jars, unless the output is a jar file itself.
return new FilteredDataEntryWriter(
new DataEntryParentFilter(
new DataEntryNameFilter(
new ExtensionMatcher(jarExtension))),
filteredJarWriter,
isJar ? jarWriter : writer);
new ExtensionMatcher(jarFilterExtension))),
// The parent of the data entry is a jar.
// Write the data entry to the jar.
// Apply the jar filter, if specified, to the parent.
jarFilter != null ?
new FilteredDataEntryWriter(
new DataEntryParentFilter(
new DataEntryNameFilter(
new ListParser(new FileNameParser()).parse(jarFilter))),
jarWriter) :
jarWriter,
// The parent of the data entry is not a jar.
// Write the entry to a jar anyway if the output is a jar.
// Otherwise just delegate to the original writer.
isOutputJar ?
jarWriter :
writer);
}
}
......@@ -43,7 +43,7 @@ import java.io.*;
*/
public class ProGuard
{
public static final String VERSION = "ProGuard, version 6.0.1";
public static final String VERSION = "ProGuard, version 6.0.3";
private final Configuration configuration;
private ClassPool programClassPool = new ClassPool();
......
......@@ -3,6 +3,20 @@
* of Java bytecode.
*
* Copyright (c) 2002-2018 GuardSquare NV
*
* This program is 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.backport;
......
......@@ -185,7 +185,8 @@ implements ClassVisitor,
for (int i = 0; i < bridgeMethodCount; i++)
{
MethodTypeConstant methodTypeConstant =
(MethodTypeConstant) programClass.getConstant(argumentIndex++);
getMethodTypeConstant(programClass,
bootstrapMethodInfo.u2methodArguments[argumentIndex++]);
lambdaExpression.bridgeMethodDescriptors =
ArrayUtil.add(lambdaExpression.bridgeMethodDescriptors,
......
......@@ -27,9 +27,12 @@ package proguard.classfile;
*/
public class ClassConstants
{
public static final byte[] JMOD_HEADER = new byte[] { 'J', 'M', 1, 0 };
public static final String WAR_CLASS_FILE_PREFIX = "classes/";
public static final String CLASS_FILE_EXTENSION = ".class";
public static final byte[] JMOD_HEADER = new byte[] { 'J', 'M', 1, 0 };
public static final String JMOD_CLASS_FILE_PREFIX = "classes/";
public static final String CLASS_FILE_EXTENSION = ".class";
public static final int MAGIC = 0xCAFEBABE;
......@@ -51,6 +54,8 @@ public class ClassConstants
public static final int CLASS_VERSION_1_8_MINOR = 0;
public static final int CLASS_VERSION_1_9_MAJOR = 53;
public static final int CLASS_VERSION_1_9_MINOR = 0;
public static final int CLASS_VERSION_10_MAJOR = 54;
public static final int CLASS_VERSION_10_MINOR = 0;
public static final int CLASS_VERSION_1_0 = (CLASS_VERSION_1_0_MAJOR << 16) | CLASS_VERSION_1_0_MINOR;
public static final int CLASS_VERSION_1_2 = (CLASS_VERSION_1_2_MAJOR << 16) | CLASS_VERSION_1_2_MINOR;
......@@ -61,6 +66,7 @@ public class ClassConstants
public static final int CLASS_VERSION_1_7 = (CLASS_VERSION_1_7_MAJOR << 16) | CLASS_VERSION_1_7_MINOR;
public static final int CLASS_VERSION_1_8 = (CLASS_VERSION_1_8_MAJOR << 16) | CLASS_VERSION_1_8_MINOR;
public static final int CLASS_VERSION_1_9 = (CLASS_VERSION_1_9_MAJOR << 16) | CLASS_VERSION_1_9_MINOR;
public static final int CLASS_VERSION_10 = (CLASS_VERSION_10_MAJOR << 16) | CLASS_VERSION_10_MINOR;
public static final int ACC_PUBLIC = 0x0001;
public static final int ACC_PRIVATE = 0x0002;
......
......@@ -44,6 +44,7 @@ public interface JavaConstants
public static final String CLASS_VERSION_1_7_ALIAS = "7";
public static final String CLASS_VERSION_1_8_ALIAS = "8";
public static final String CLASS_VERSION_1_9_ALIAS = "9";
public static final String CLASS_VERSION_10 = "10";
public static final String ACC_PUBLIC = "public";
public static final String ACC_PRIVATE = "private";
......@@ -92,4 +93,4 @@ public interface JavaConstants
public static final String TYPE_LONG = "long";
public static final String TYPE_DOUBLE = "double";
public static final String TYPE_ARRAY = "[]";
}
\ No newline at end of file
}
......@@ -23,7 +23,6 @@ package proguard.classfile.attribute.visitor;
import proguard.classfile.Clazz;
import proguard.classfile.attribute.BootstrapMethodInfo;
/**
* This interface specifies the methods for a visitor of
* <code>BootstrapMethodInfo</code> objects. Note that there is only a single
......
......@@ -28,19 +28,18 @@ import proguard.classfile.attribute.visitor.BootstrapMethodInfoVisitor;
* This BootstrapMethodInfoVisitor lets a given ConstantVisitor visit all
* constant pool entries of the bootstrap methods it visits.
*
*
* @author Eric Lafortune
*/
public class BootstrapMethodArgumentVisitor
public class AllBootstrapMethodArgumentVisitor
implements BootstrapMethodInfoVisitor
{
private ConstantVisitor constantVisitor;
/**
* Creates a new BootstrapMethodArgumentVisitor that will delegate to the
* given constant visitor.
* Creates a new AllBootstrapMethodArgumentVisitor that will delegate to
* the given constant visitor.
*/
public BootstrapMethodArgumentVisitor(ConstantVisitor constantVisitor)
public AllBootstrapMethodArgumentVisitor(ConstantVisitor constantVisitor)
{
this.constantVisitor = constantVisitor;
}
......@@ -50,7 +49,6 @@ implements BootstrapMethodInfoVisitor
public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo)
{
// Check bootstrap method.
bootstrapMethodInfo.methodArgumentsAccept(clazz, constantVisitor);
}
}
......@@ -21,8 +21,13 @@
package proguard.classfile.editor;
import proguard.classfile.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.annotation.*;
import proguard.classfile.attribute.annotation.visitor.AllElementValueVisitor;
import proguard.classfile.attribute.visitor.*;
import proguard.classfile.constant.*;
import proguard.classfile.constant.visitor.ConstantVisitor;
import proguard.classfile.instruction.*;
import proguard.classfile.instruction.visitor.*;
import proguard.classfile.util.*;
import proguard.classfile.visitor.*;
......@@ -33,164 +38,155 @@ import proguard.classfile.visitor.*;
* @author Eric Lafortune
*/
public class AccessFixer
extends ReferencedClassVisitor
implements ClassVisitor
{
private final ConstantVisitor referencedClassStorer = new MyReferencedClassStorer();
private final ClassVisitor referencedClassFixer =
new ReferencedClassVisitor(
new MyReferencedClassAccessFixer());
private final ClassVisitor referencedMemberFixer =
new AllMethodVisitor(
new AllAttributeVisitor(
new AllInstructionVisitor(
new MyReferencedMemberVisitor(
new MyReferencedMemberAccessFixer()))));
/**
* Creates a new AccessFixer.
*/
public AccessFixer()
{
// Unfortunately, the inner class must be static to be passed to the
// super constructor. We therefore can't let it refer to this class;
// we'll let this class refer to the inner class instead.
super(new MyAccessFixer());
}
private final ClassVisitor referencedAnnotationMethodFixer =
new AllAttributeVisitor(true,
new AllElementValueVisitor(
new MyReferencedMemberVisitor(
new MyReferencedMemberAccessFixer())));
private final ClassVisitor methodHierarchyFixer =
new AllMethodVisitor(
new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE |
ClassConstants.ACC_STATIC,
new InitializerMethodFilter(null,
new SimilarMemberVisitor(false, true, false, true,
new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE |
ClassConstants.ACC_STATIC,
new MyReferencedMemberAccessFixer())))));
// Overridden methods for ClassVisitor.
// Fields acting as parameters for the visitors.
public void visitProgramClass(ProgramClass programClass)
{
// Remember the referencing class.
((MyAccessFixer)classVisitor).referencingClass = programClass;
private Clazz referencingClass;
private int referencingMethodAccessFlags;
private Clazz referencedClass;
// Start visiting and fixing the referenced classes and class members.
super.visitProgramClass(programClass);
}
// Implementations for ClassVisitor.
public void visitLibraryClass(LibraryClass libraryClass) {}
public void visitLibraryClass(LibraryClass libraryClass)
public void visitProgramClass(ProgramClass programClass)
{
// Remember the referencing class.
((MyAccessFixer)classVisitor).referencingClass = libraryClass;
referencingClass = programClass;
// Start visiting and fixing the referenced classes and class members.
super.visitLibraryClass(libraryClass);
}
// Fix the referenced classes.
referencedClassFixer.visitProgramClass(programClass);
// Fix the referenced class members.
referencedMemberFixer.visitProgramClass(programClass);
// Overridden methods for MemberVisitor.
// Fix the referenced annotation methods.
referencedAnnotationMethodFixer.visitProgramClass(programClass);
public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
// Fix the referenced classes and class members.
super.visitProgramMember(programClass, programMethod);
// Fix overridden or implemented methods higher up the hierarchy.
// We can ignore private and static methods and initializers.
if ((programMethod.getAccessFlags() & (ClassConstants.ACC_PRIVATE |
ClassConstants.ACC_STATIC)) == 0 &&
!ClassUtil.isInitializer(programMethod.getName(programClass)))
{
programClass.hierarchyAccept(false, true, false, false,
new NamedMethodVisitor(programMethod.getName(programClass),
programMethod.getDescriptor(programClass),
new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE |
ClassConstants.ACC_STATIC,
(MemberVisitor)classVisitor)));
}
// Fix overridden and overriding methods up and down the hierarchy.
// They are referenced implicitly and need to be accessible too.
referencingMethodAccessFlags = 0;
referencedClass = null;
methodHierarchyFixer.visitProgramClass(programClass);
}
public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
/**
* This ReferencedMemberVisitor is an InstructionVisitor that also
* remembers the access flags of the referencing methods, and the
* referenced class.
*/
private class MyReferencedMemberVisitor
extends ReferencedMemberVisitor
implements InstructionVisitor
{
// Fix the referenced classes and class members.
super.visitLibraryMember(libraryClass, libraryMethod);
// Fix overridden or implemented methods higher up the hierarchy.
// We can ignore private and static methods and initializers.
if ((libraryMethod.getAccessFlags() & (ClassConstants.ACC_PRIVATE |
ClassConstants.ACC_STATIC)) == 0 &&
!ClassUtil.isInitializer(libraryMethod.getName(libraryClass)))
public MyReferencedMemberVisitor(MemberVisitor memberVisitor)
{
libraryClass.hierarchyAccept(false, true, false, false,
new NamedMethodVisitor(libraryMethod.getName(libraryClass),
libraryMethod.getDescriptor(libraryClass),
new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE |
ClassConstants.ACC_STATIC,
(MemberVisitor)classVisitor)));
super(memberVisitor);
}
}
// Overridden methods for ConstantVisitor.
// Implementations for InstructionVisitor.
public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
{
// Fix the access flags of the referenced class, if any.
super.visitStringConstant(clazz, stringConstant);
// Fix the access flags of the referenced class member, if any.
stringConstant.referencedMemberAccept((MemberVisitor)classVisitor);
}
public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
{
// Remember the referenced class. Note that we're interested in the
// class of the invocation, not in the class in which the member was
// actually found, unless it is an array type.
if (ClassUtil.isInternalArrayType(refConstant.getClassName(clazz)))
public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
{
// For an array type, the class will be java.lang.Object.
((MyAccessFixer)classVisitor).referencedClass =
refConstant.referencedClass;
}
else
{
// Remember the referenced class.
clazz.constantPoolEntryAccept(refConstant.u2classIndex,
referencedClassStorer);
// Remember the access flags.
referencingMethodAccessFlags = method.getAccessFlags();
// Fix the referenced classes and class members.
clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
}
// Fix the access flags of the class of the referenced class member.
super.visitAnyRefConstant(clazz, refConstant);
// Fix the access flags of the referenced class member.
refConstant.referencedMemberAccept((MemberVisitor)classVisitor);
}
// Overridden methods for ConstantVisitor.
public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
{
// Remember the referenced class. Note that we're interested in the
// class of the invocation, not in the class in which the member was
// actually found, unless it is an array type.
if (ClassUtil.isInternalArrayType(refConstant.getClassName(clazz)))
{
// For an array type, the class will be java.lang.Object.
referencedClass = refConstant.referencedClass;
}
else
{
// Remember the referenced class.
clazz.constantPoolEntryAccept(refConstant.u2classIndex, this);
}
// Fix the access flags of referenced class member.
super.visitAnyRefConstant(clazz, refConstant);
}
/**
* This ConstantVisitor stores the classes referenced by the class
* constants that it visits.
*/
private class MyReferencedClassStorer
extends SimplifiedVisitor
implements ConstantVisitor
{
// Implementations for ConstantVisitor.
public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
{
// Remember the referenced class.
((MyAccessFixer)classVisitor).referencedClass =
classConstant.referencedClass;
referencedClass = classConstant.referencedClass;
}
// Implementations for ElementValueVisitor.
public void visitAnyElementValue(Clazz clazz, Annotation annotation, ElementValue elementValue)
{
// Set the referencing access flags and set the referenced class.
referencingMethodAccessFlags = ClassConstants.ACC_STATIC;
referencedClass = elementValue.referencedClass;
// Fix the access flags of referenced annotation method.
super.visitAnyElementValue(clazz, annotation, elementValue);
}
}
/**
* This ClassVisitor and MemberVisitor fixes the access flags of the
* classes and class members that it visits, relative to the referencing
* class.
*
* This class must be static so it can be passed to the super constructor
* of the outer class.
* This ClassVisitor fixes the access flags of the classes that it visits,
* relative to the referencing class.
*/
private static class MyAccessFixer
extends SimplifiedVisitor
implements ClassVisitor,
MemberVisitor
private class MyReferencedClassAccessFixer
extends SimplifiedVisitor
implements ClassVisitor,
AttributeVisitor,
InnerClassesInfoVisitor
{
private Clazz referencingClass;
private Clazz referencedClass;
// Implementations for ClassVisitor.
public void visitLibraryClass(LibraryClass libraryClass) {}
......@@ -198,25 +194,86 @@ implements ClassVisitor
public void visitProgramClass(ProgramClass programClass)
{
// Do we need to update the access flags?
int currentAccessFlags = programClass.getAccessFlags();
int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags);
if (currentAccessLevel < AccessUtil.PUBLIC)
{
// Compute the required access level.
int requiredAccessLevel =
inSamePackage(programClass, referencingClass) ?
AccessUtil.PACKAGE_VISIBLE :
AccessUtil.PUBLIC;
// Fix the class access flags if necessary.
if (currentAccessLevel < requiredAccessLevel)
{
programClass.u2accessFlags =
AccessUtil.replaceAccessFlags(currentAccessFlags,
AccessUtil.accessFlags(requiredAccessLevel));
}
}
// Also check the InnerClasses attribute, if any.
programClass.attributesAccept(this);
}
// Implementations for AttributeVisitor.
public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
// Compute the required access level.
int requiredAccessLevel =
inSamePackage(programClass, referencingClass) ?
AccessUtil.PACKAGE_VISIBLE :
AccessUtil.PUBLIC;
// Fix the class access flags if necessary.
if (currentAccessLevel < requiredAccessLevel)
public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
{
innerClassesAttribute.innerClassEntriesAccept(clazz, this);
}
// Implementations for InnerClassesInfoVisitor.
public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)
{
// Is this an inner class?
int innerClassIndex = innerClassesInfo.u2innerClassIndex;
if (innerClassIndex != 0)
{
programClass.u2accessFlags =
AccessUtil.replaceAccessFlags(currentAccessFlags,
AccessUtil.accessFlags(requiredAccessLevel));
String innerClassName = clazz.getClassName(innerClassIndex);
if (innerClassName.equals(clazz.getName()))
{
// Do we need to update the access flags?
int currentAccessFlags = innerClassesInfo.u2innerClassAccessFlags;
int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags);
if (currentAccessLevel < AccessUtil.PUBLIC)
{
// Compute the required access level.
int requiredAccessLevel =
inSamePackage(clazz, referencingClass) ?
AccessUtil.PACKAGE_VISIBLE :
AccessUtil.PUBLIC;
// Fix the inner class access flags if necessary.
if (currentAccessLevel < requiredAccessLevel)
{
innerClassesInfo.u2innerClassAccessFlags =
AccessUtil.replaceAccessFlags(currentAccessFlags,
AccessUtil.accessFlags(requiredAccessLevel));
}
}
}
}
}
}
/**
* This MemberVisitor fixes the access flags of the class members that it
* visits, relative to the referencing class and method.
*/
private class MyReferencedMemberAccessFixer
extends SimplifiedVisitor
implements MemberVisitor
{
// Implementations for MemberVisitor.
public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember) {}
......@@ -224,39 +281,44 @@ implements ClassVisitor
public void visitProgramMember(ProgramClass programClass, ProgramMember programMember)
{
// Do we need to update the access flags?
int currentAccessFlags = programMember.getAccessFlags();
int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags);
// Compute the required access level.
// For protected access, we're taking into account the class in the
// invocation and the class that actually contains the member.
int requiredAccessLevel =
programClass.equals(referencingClass) ? AccessUtil.PRIVATE :
inSamePackage(programClass, referencingClass) ? AccessUtil.PACKAGE_VISIBLE :
referencedClass != null &&
referencingClass.extends_(referencedClass) &&
referencingClass.extends_(programClass) ? AccessUtil.PROTECTED :
AccessUtil.PUBLIC;
// Fix the class member access flags if necessary.
if (currentAccessLevel < requiredAccessLevel)
if (currentAccessLevel < AccessUtil.PUBLIC)
{
programMember.u2accessFlags =
AccessUtil.replaceAccessFlags(currentAccessFlags,
AccessUtil.accessFlags(requiredAccessLevel));
// Compute the required access level.
// For protected access, the referencing method may not be
// static. We're also taking into account the class in the
// invocation and the class that actually contains the member.
int requiredAccessLevel =
programClass.equals(referencingClass) ? AccessUtil.PRIVATE :
inSamePackage(programClass, referencingClass) ? AccessUtil.PACKAGE_VISIBLE :
(referencingMethodAccessFlags & ClassConstants.ACC_STATIC) == 0 &&
(referencedClass == null ||
referencingClass.extends_(referencedClass)) &&
referencingClass.extends_(programClass) ? AccessUtil.PROTECTED :
AccessUtil.PUBLIC;
// Fix the class member access flags if necessary.
if (currentAccessLevel < requiredAccessLevel)
{
programMember.u2accessFlags =
AccessUtil.replaceAccessFlags(currentAccessFlags,
AccessUtil.accessFlags(requiredAccessLevel));
}
}
}
}
// Small utility methods.
// Small utility methods.
/**
* Returns whether the two given classes are in the same package.
*/
private boolean inSamePackage(Clazz class1, Clazz class2)
{
return ClassUtil.internalPackageName(class1.getName()).equals(
ClassUtil.internalPackageName(class2.getName()));
}
/**
* Returns whether the two given classes are in the same package.
*/
private boolean inSamePackage(Clazz class1, Clazz class2)
{
return ClassUtil.internalPackageName(class1.getName()).equals(
ClassUtil.internalPackageName(class2.getName()));
}
}
......@@ -106,6 +106,7 @@ public class ClassUtil
externalClassVersion.equals(JavaConstants.CLASS_VERSION_1_8) ? ClassConstants.CLASS_VERSION_1_8 :
externalClassVersion.equals(JavaConstants.CLASS_VERSION_1_9_ALIAS) ||
externalClassVersion.equals(JavaConstants.CLASS_VERSION_1_9) ? ClassConstants.CLASS_VERSION_1_9 :
externalClassVersion.equals(JavaConstants.CLASS_VERSION_10) ? ClassConstants.CLASS_VERSION_10 :
0;
}
......@@ -128,6 +129,7 @@ public class ClassUtil
case ClassConstants.CLASS_VERSION_1_7: return JavaConstants.CLASS_VERSION_1_7;
case ClassConstants.CLASS_VERSION_1_8: return JavaConstants.CLASS_VERSION_1_8;
case ClassConstants.CLASS_VERSION_1_9: return JavaConstants.CLASS_VERSION_1_9;
case ClassConstants.CLASS_VERSION_10: return JavaConstants.CLASS_VERSION_10;
default: return null;
}
}
......@@ -141,14 +143,14 @@ public class ClassUtil
public static void checkVersionNumbers(int internalClassVersion) throws UnsupportedOperationException
{
if (internalClassVersion < ClassConstants.CLASS_VERSION_1_0 ||
internalClassVersion > ClassConstants.CLASS_VERSION_1_9)
internalClassVersion > ClassConstants.CLASS_VERSION_10)
{
throw new UnsupportedOperationException("Unsupported version number ["+
internalMajorClassVersion(internalClassVersion)+"."+
internalMinorClassVersion(internalClassVersion)+"] (maximum "+
ClassConstants.CLASS_VERSION_1_9_MAJOR+"."+
ClassConstants.CLASS_VERSION_1_9_MINOR+", Java "+
JavaConstants.CLASS_VERSION_1_9+")");
ClassConstants.CLASS_VERSION_10_MAJOR+"."+
ClassConstants.CLASS_VERSION_10_MINOR+", Java "+
JavaConstants.CLASS_VERSION_10+")");
}
}
......
/*
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
* Copyright (c) 2002-2018 GuardSquare NV
*
* This program is 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.visitor;
import proguard.classfile.*;
import proguard.classfile.constant.*;
import proguard.classfile.constant.visitor.ConstantVisitor;
import proguard.classfile.util.SimplifiedVisitor;
import proguard.util.ArrayUtil;
/**
* This ConstantVisitor delegates all visits to each ConstantVisitor in a given list.
*
* @author Johan Leys
*/
public class MultiConstantVisitor
extends SimplifiedVisitor
implements ConstantVisitor
{
private ConstantVisitor[] constantVisitors;
private int constantVisitorCount;
public MultiConstantVisitor()
{
this.constantVisitors = new ConstantVisitor[16];
}
public MultiConstantVisitor(ConstantVisitor... constantVisitors)
{
this.constantVisitors = constantVisitors;
this.constantVisitorCount = this.constantVisitors.length;
}
public void addClassVisitor(ConstantVisitor constantVisitor)
{
constantVisitors =
ArrayUtil.add(constantVisitors,
constantVisitorCount++,
constantVisitor);
}
// Implementations for ConstantVisitor.
public void visitAnyConstant(Clazz clazz, Constant constant)
{
for (int index = 0; index < constantVisitorCount; index++)
{
constant.accept(clazz, constantVisitors[index]);
}
}
}
......@@ -38,7 +38,7 @@ extends SimplifiedVisitor
implements ConstantVisitor,
ElementValueVisitor
{
private final MemberVisitor memberVisitor;
protected final MemberVisitor memberVisitor;
public ReferencedMemberVisitor(MemberVisitor memberVisitor)
......
......@@ -25,7 +25,7 @@ import proguard.classfile.*;
/**
* This <code>MemberVisitor</code> lets a given <code>MemberVisitor</code>
* visit all members that have the same name and type as the visited methods
* in the class hierarchy of a given target class.
* in the class hierarchy of the members' classes or of a given target class.
*
* @author Eric Lafortune
*/
......@@ -40,6 +40,37 @@ implements MemberVisitor
private final MemberVisitor memberVisitor;
/**
* Creates a new SimilarMemberVisitor.
* @param visitThisMember specifies whether to visit the class
* members in the members' classes themselves.
* @param visitSuperMembers specifies whether to visit the class
* members in the super classes of the
* members' classes.
* @param visitInterfaceMembers specifies whether to visit the class
* members in the interface classes of the
* members' classes.
* @param visitOverridingMembers specifies whether to visit the class
* members in the subclasses of the members'
* classes.
* @param memberVisitor the <code>MemberVisitor</code> to which
* visits will be delegated.
*/
public SimilarMemberVisitor(boolean visitThisMember,
boolean visitSuperMembers,
boolean visitInterfaceMembers,
boolean visitOverridingMembers,
MemberVisitor memberVisitor)
{
this(null,
visitThisMember,
visitSuperMembers,
visitInterfaceMembers,
visitOverridingMembers,
memberVisitor);
}
/**
* Creates a new SimilarMemberVisitor.
* @param targetClass the class in whose hierarchy to look for
......@@ -78,6 +109,8 @@ implements MemberVisitor
public void visitProgramField(ProgramClass programClass, ProgramField programField)
{
Clazz targetClass = targetClass(programClass);
targetClass.hierarchyAccept(visitThisMember,
visitSuperMembers,
visitInterfaceMembers,
......@@ -90,6 +123,8 @@ implements MemberVisitor
public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
{
Clazz targetClass = targetClass(libraryClass);
targetClass.hierarchyAccept(visitThisMember,
visitSuperMembers,
visitInterfaceMembers,
......@@ -102,6 +137,8 @@ implements MemberVisitor
public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
{
Clazz targetClass = targetClass(programClass);
targetClass.hierarchyAccept(visitThisMember,
visitSuperMembers,
visitInterfaceMembers,
......@@ -114,6 +151,8 @@ implements MemberVisitor
public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
{
Clazz targetClass = targetClass(libraryClass);
targetClass.hierarchyAccept(visitThisMember,
visitSuperMembers,
visitInterfaceMembers,
......@@ -122,4 +161,14 @@ implements MemberVisitor
libraryMethod.getDescriptor(libraryClass),
memberVisitor));
}
/**
* Returns the target class, or the given class if the target class is
* null.
*/
private Clazz targetClass(Clazz clazz)
{
return targetClass != null ? targetClass : clazz;
}
}
\ No newline at end of file
......@@ -26,7 +26,8 @@ import java.io.*;
import java.util.Date;
/**
* This DataEntryWriter sends data entries to a given jar/zip file.
* This DataEntryWriter sends data entries to a the jar/zip files specified by
* their parents.
*
* @author Eric Lafortune
*/
......