Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unreferenced class detection #598

Open
wants to merge 5 commits into
base: dev3
Choose a base branch
from

Conversation

yapht
Copy link
Contributor

@yapht yapht commented Sep 1, 2022

What's new

  • Classes are now aware of their source type (primary, library, internal library, phantom generated)
  • Add system for tracking classes that are referenced by code that will execute at runtime, this allows us to show a warning for unused classes when you try to decompile them.

@yapht yapht changed the title Feature/unrefclasswarning Unreferenced class detection Sep 1, 2022
Copy link
Owner

@Col-E Col-E left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good, few minor comments thus far.

private void addClasses(String descriptor) {
MatchIterator it = TYPE_PATTERN.matcher(descriptor).findAll();
if (!it.hasMore()) return;
while (it.hasMore()) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can use ASM's Type class to parse this more efficiently.

Also, further down in this review I have a suggestion which will ensure only single-value descriptors (no method descriptors) will be passed in here. This should actually let us be even quicker by doing descriptor.substring(1, descriptor.length() - 1) assuming the descriptor is an object type. We can check by: descriptor.size() > 2 && descriptor.charAt(0) == 'L'


@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
types.add(descriptor);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be things like (ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)Lorg/objectweb/asm/MethodVisitor;

We can sanitize our input such that types never has method types to make handling values simpler later.

Using ASM's Type class we can parse the method descriptor and add each parameter type & return value.

return new TypeCollectionMethodVisitor(types, methodVisitor);
}

return super.visitMethod(access, name, descriptor, signature, exceptions);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If shouldVisitMethods is false we can return null to skip over some data that won't be looked at.

@Override
public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
types.add(descriptor);
return super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May want to also create an annotation visitor. For example @MyAnno(myEnumValue = Foo.VALUE_FOO) may be the only case where the type Foo is referenced.

@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
types.add(owner);
types.add(descriptor);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing as described before with adding only single values to types rather than whole method descriptors.

Applies to invokedynamic too.

@@ -52,7 +53,7 @@ protected void onRead(ContentCollection collection) throws IOException {
try {
if (isParsableClass(bytes)) {
// Class can be parsed, record it as a class
ClassInfo clazz = ClassInfo.read(bytes);
ClassInfo clazz = ClassInfo.read(bytes, ClassSourceType.PRIMARY);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think we cannot assume this is a library at this point. For instance, how would we differentiate between when the user drops a jar in and chooses "add as library" instead of opening a new workspace?

…ning

# Conflicts:
#	recaf-core/src/main/java/me/coley/recaf/Services.java
#	recaf-core/src/main/java/me/coley/recaf/code/ClassInfo.java
#	recaf-core/src/main/java/me/coley/recaf/workspace/resource/RuntimeResource.java
#	recaf-ui/src/main/java/me/coley/recaf/ui/control/code/bytecode/AssemblerArea.java
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants