| /* |
| * ProGuard -- shrinking, optimization, obfuscation, and preverification |
| * of Java bytecode. |
| * |
| * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu) |
| * |
| * This program is 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 ClassVisitor and MemberVisitor recursively marks all classes |
| * and class elements that are being used. For each element, it finds the |
| * shortest chain of dependencies. |
| * |
| * @see ClassShrinker |
| * |
| * @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 final MyRecursiveCauseChecker recursiveCauseChecker = new MyRecursiveCauseChecker(); |
| |
| |
| // Overriding implementations for UsageMarker. |
| |
| protected void markProgramClassBody(ProgramClass programClass) |
| { |
| ShortestUsageMark previousUsageMark = currentUsageMark; |
| |
| currentUsageMark = new ShortestUsageMark(getShortestUsageMark(programClass), |
| "is extended by ", |
| 10000, |
| programClass); |
| |
| super.markProgramClassBody(programClass); |
| |
| currentUsageMark = previousUsageMark; |
| } |
| |
| |
| protected void markProgramFieldBody(ProgramClass programClass, ProgramField programField) |
| { |
| ShortestUsageMark previousUsageMark = currentUsageMark; |
| |
| currentUsageMark = new ShortestUsageMark(getShortestUsageMark(programField), |
| "is referenced by ", |
| 1, |
| programClass, |
| programField); |
| |
| super.markProgramFieldBody(programClass, programField); |
| |
| currentUsageMark = previousUsageMark; |
| } |
| |
| |
| protected void markProgramMethodBody(ProgramClass programClass, ProgramMethod programMethod) |
| { |
| ShortestUsageMark previousUsageMark = currentUsageMark; |
| |
| currentUsageMark = new ShortestUsageMark(getShortestUsageMark(programMethod), |
| "is invoked by ", |
| 1, |
| programClass, |
| programMethod); |
| |
| super.markProgramMethodBody(programClass, programMethod); |
| |
| currentUsageMark = previousUsageMark; |
| } |
| |
| |
| protected void markMethodHierarchy(Clazz clazz, Method method) |
| { |
| ShortestUsageMark previousUsageMark = currentUsageMark; |
| |
| currentUsageMark = new ShortestUsageMark(getShortestUsageMark(method), |
| "implements ", |
| 100, |
| clazz, |
| method); |
| |
| super.markMethodHierarchy(clazz, method); |
| |
| 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 Clazz && |
| // isCausedBy(currentUsageMark, (Clazz)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, |
| Clazz clazz) |
| { |
| return recursiveCauseChecker.check(shortestUsageMark, clazz); |
| } |
| |
| |
| private class MyRecursiveCauseChecker implements ClassVisitor, MemberVisitor |
| { |
| private Clazz checkClass; |
| private boolean isRecursing; |
| |
| |
| public boolean check(ShortestUsageMark shortestUsageMark, |
| Clazz clazz) |
| { |
| checkClass = clazz; |
| isRecursing = false; |
| |
| shortestUsageMark.acceptClassVisitor(this); |
| shortestUsageMark.acceptMemberVisitor(this); |
| |
| return isRecursing; |
| } |
| |
| // Implementations for ClassVisitor. |
| |
| public void visitProgramClass(ProgramClass programClass) |
| { |
| checkCause(programClass); |
| } |
| |
| |
| public void visitLibraryClass(LibraryClass libraryClass) |
| { |
| checkCause(libraryClass); |
| } |
| |
| |
| // Implementations for MemberVisitor. |
| |
| public void visitProgramField(ProgramClass programClass, ProgramField programField) |
| { |
| checkCause(programField); |
| } |
| |
| |
| public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) |
| { |
| checkCause(programMethod); |
| } |
| |
| |
| public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) |
| { |
| checkCause(libraryField); |
| } |
| |
| |
| public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) |
| { |
| checkCause(libraryMethod); |
| } |
| |
| |
| // 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(checkClass); |
| |
| // Check the causing class or method, if still necessary. |
| if (!isRecursing) |
| { |
| shortestUsageMark.acceptClassVisitor(this); |
| shortestUsageMark.acceptMemberVisitor(this); |
| } |
| } |
| } |
| } |
| } |