Skip to content

Commit

Permalink
add ProjectClassProvider (#226)
Browse files Browse the repository at this point in the history
* graaaah

(cherry picked from commit 4a1a27c)

* restore library indexing system

* put scope back

* review
  • Loading branch information
ix0rai authored Sep 18, 2024
1 parent 718e671 commit d2e9071
Show file tree
Hide file tree
Showing 17 changed files with 142 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.quiltmc.enigma.api.class_provider.CachingClassProvider;
import org.quiltmc.enigma.api.class_provider.ClasspathClassProvider;
import org.quiltmc.enigma.api.class_provider.JarClassProvider;
import org.quiltmc.enigma.api.class_provider.ProjectClassProvider;
import org.quiltmc.enigma.api.translation.mapping.EntryMapping;
import org.quiltmc.enigma.api.translation.mapping.MappingDelta;
import org.quiltmc.enigma.api.translation.mapping.serde.MappingParseException;
Expand Down Expand Up @@ -108,7 +109,7 @@ public static JarIndex loadJar(Path jar) throws IOException {
Logger.info("Reading JAR...");
JarClassProvider classProvider = new JarClassProvider(jar);
JarIndex index = MainJarIndex.empty();
index.indexJar(classProvider.getClassNames(), new CachingClassProvider(classProvider), ProgressListener.createEmpty());
index.indexJar(new ProjectClassProvider(new CachingClassProvider(classProvider), null), ProgressListener.createEmpty());

return index;
}
Expand Down
19 changes: 9 additions & 10 deletions enigma/src/main/java/org/quiltmc/enigma/api/Enigma.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.quiltmc.enigma.api.analysis.index.jar.LibrariesJarIndex;
import org.quiltmc.enigma.api.analysis.index.jar.MainJarIndex;
import org.quiltmc.enigma.api.analysis.index.mapping.MappingsIndex;
import org.quiltmc.enigma.api.class_provider.ProjectClassProvider;
import org.quiltmc.enigma.impl.analysis.ClassLoaderClassProvider;
import org.quiltmc.enigma.api.service.EnigmaService;
import org.quiltmc.enigma.api.service.EnigmaServiceContext;
Expand Down Expand Up @@ -43,13 +44,11 @@
import java.sql.DriverManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;

public class Enigma {
Expand Down Expand Up @@ -85,14 +84,13 @@ public EnigmaProject openJar(Path path, ClassProvider libraryClassProvider, Prog
ClassLoaderClassProvider jreProvider = new ClassLoaderClassProvider(DriverManager.class.getClassLoader());
CombiningClassProvider librariesProvider = new CombiningClassProvider(jreProvider, libraryClassProvider);
ClassProvider mainProjectProvider = new ObfuscationFixClassProvider(new CachingClassProvider(jarClassProvider), index);

Set<String> mainScope = new HashSet<>(mainProjectProvider.getClassNames());
Set<String> librariesScope = new HashSet<>(librariesProvider.getClassNames());
ProjectClassProvider projectClassProvider = new ProjectClassProvider(mainProjectProvider, librariesProvider);

// main index
this.index(index, mainProjectProvider, mainScope, progress, false);
this.index(index, projectClassProvider, progress);

// lib index
this.index(libIndex, librariesProvider, librariesScope, progress, true);
this.index(libIndex, projectClassProvider, progress);

// name proposal
var nameProposalServices = this.getNameProposalServices();
Expand Down Expand Up @@ -124,9 +122,10 @@ public EnigmaProject openJar(Path path, ClassProvider libraryClassProvider, Prog
return new EnigmaProject(this, path, mainProjectProvider, index, libIndex, mappingsIndex, proposedNames, Utils.zipSha1(path));
}

private void index(JarIndex index, ClassProvider classProvider, Set<String> scope, ProgressListener progress, boolean libraries) {
private void index(JarIndex index, ProjectClassProvider classProvider, ProgressListener progress) {
boolean libraries = index instanceof LibrariesJarIndex;
String progressKey = libraries ? "libs" : "jar";
index.indexJar(scope, classProvider, progress);
index.indexJar(classProvider, progress);

List<JarIndexerService> indexers = this.services.get(JarIndexerService.TYPE);
progress.init(indexers.size(), I18n.translate("progress." + progressKey + ".custom_indexing"));
Expand All @@ -135,7 +134,7 @@ private void index(JarIndex index, ClassProvider classProvider, Set<String> scop
for (var service : indexers) {
if (!(libraries && !service.shouldIndexLibraries())) {
progress.step(i++, I18n.translateFormatted("progress." + progressKey + ".custom_indexing.indexer", service.getId()));
service.acceptJar(scope, classProvider, index);
service.acceptJar(libraries ? classProvider.getLibraryClassNames() : classProvider.getMainClassNames(), classProvider, index);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@

import com.google.common.collect.ListMultimap;
import org.quiltmc.enigma.api.ProgressListener;
import org.quiltmc.enigma.api.class_provider.ClassProvider;
import org.quiltmc.enigma.api.class_provider.ProjectClassProvider;
import org.quiltmc.enigma.api.translation.mapping.EntryResolver;
import org.quiltmc.enigma.api.translation.representation.entry.ClassEntry;
import org.quiltmc.enigma.api.translation.representation.entry.ParentedEntry;

import java.util.Set;

public interface JarIndex extends JarIndexer {
/**
* Gets the index associated with the provided class.
Expand All @@ -19,11 +17,10 @@ public interface JarIndex extends JarIndexer {

/**
* Runs every configured indexer over the provided jar.
* @param classNames the obfuscated names of each class in the jar
* @param classProvider a class provider containing all classes in the jar
* @param classProvider a class provider containing all classes in the jar and libraries
* @param progress a progress listener to track index completion
*/
void indexJar(Set<String> classNames, ClassProvider classProvider, ProgressListener progress);
void indexJar(ProjectClassProvider classProvider, ProgressListener progress);

/**
* {@return an entry resolver with this index's contents as context}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.quiltmc.enigma.api.analysis.index.jar;

import org.quiltmc.enigma.api.ProgressListener;
import org.quiltmc.enigma.api.class_provider.ProjectClassProvider;
import org.quiltmc.enigma.impl.analysis.index.AbstractJarIndex;

public class LibrariesJarIndex extends AbstractJarIndex {
Expand All @@ -22,4 +24,9 @@ public static JarIndex empty() {
public String getTranslationKey() {
return "progress.jar.indexing.libraries";
}

@Override
public void indexJar(ProjectClassProvider classProvider, ProgressListener progress) {
this.indexJar(classProvider.getLibraryClassNames(), classProvider, progress);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.quiltmc.enigma.api.analysis.index.jar;

import org.quiltmc.enigma.api.ProgressListener;
import org.quiltmc.enigma.api.class_provider.ProjectClassProvider;
import org.quiltmc.enigma.impl.analysis.index.AbstractJarIndex;

public class MainJarIndex extends AbstractJarIndex {
Expand All @@ -26,4 +28,9 @@ public static JarIndex empty() {
public String getTranslationKey() {
return "progress.jar.indexing.jar";
}

@Override
public void indexJar(ProjectClassProvider classProvider, ProgressListener progress) {
this.indexJar(classProvider.getMainClassNames(), classProvider, progress);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public ObfuscationFixClassProvider(ClassProvider classProvider, JarIndex jarInde
public ClassNode get(String name) {
ClassNode node = this.classProvider.get(name);

if (!this.jarIndex.isIndexed(name)) {
if (!this.jarIndex.isIndexed(name) || node == null) {
return node;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package org.quiltmc.enigma.api.class_provider;

import org.objectweb.asm.tree.ClassNode;

import javax.annotation.Nullable;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

public class ProjectClassProvider implements ClassProvider {
@Nullable
private final ClassProvider main;
@Nullable
private final ClassProvider libraries;
private final Collection<String> classNames;

public ProjectClassProvider(@Nullable ClassProvider main, @Nullable ClassProvider libraries) {
if (main == null && libraries == null) {
throw new InvalidParameterException("cannot create a project class provider with both main and library providers as null!");
}

this.main = main;
this.libraries = libraries;
this.classNames = new ArrayList<>();
if (main != null) {
this.classNames.addAll(main.getClassNames());
}

if (libraries != null) {
this.classNames.addAll(libraries.getClassNames());
}
}

@Nullable
@Override
public ClassNode get(String name) {
// i hate working with nullability and am a bad programmer. btw
ClassNode mainNode;
if (this.main != null) {
mainNode = this.main.get(name);
if (mainNode != null) {
return mainNode;
}
}

if (this.libraries != null) {
return this.libraries.get(name);
}

return null;
}

/**
* Gets the {@linkplain ClassNode} for a class in the main JAR file. The class provider may return a cached result,
* so it's important to not mutate it.
*
* @param name the internal name of the class
* @return the {@linkplain ClassNode} for that class, or {@code null} if it was not found
*/
public @Nullable ClassNode getMainClass(String name) {
return this.main != null ? this.main.get(name) : null;
}

/**
* Gets the {@linkplain ClassNode} for a class in the provided libraries. The class provider may return a cached result,
* so it's important to not mutate it.
*
* @param name the internal name of the class
* @return the {@linkplain ClassNode} for that class, or {@code null} if it was not found
*/
public @Nullable ClassNode getLibraryClass(String name) {
return this.libraries != null ? this.libraries.get(name) : null;
}

@Override
public Collection<String> getClassNames() {
return this.classNames;
}

public Collection<String> getMainClassNames() {
return this.main != null ? this.main.getClassNames() : Collections.emptySet();
}

public Collection<String> getLibraryClassNames() {
return this.libraries != null ? this.libraries.getClassNames() : Collections.emptySet();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

import org.objectweb.asm.tree.ClassNode;
import org.quiltmc.enigma.api.analysis.index.jar.JarIndex;
import org.quiltmc.enigma.api.class_provider.ClassProvider;
import org.objectweb.asm.ClassVisitor;
import org.quiltmc.enigma.api.class_provider.ProjectClassProvider;

import javax.annotation.Nullable;
import java.util.Set;
import java.util.Collection;

/**
* Jar indexer services analyse jar files as they're opened to collect information about their contents.
Expand All @@ -31,11 +31,11 @@ static boolean shouldIndexLibraries(@Nullable EnigmaServiceContext<JarIndexerSer

/**
* Indexes a collection of classes.
* @param scope a list of class names to be indexed
* @param classProvider a provider to translate class names into {@link ClassNode class nodes}
* @param scope the current scope to be indexed. This is either all main jar classes or all library classes
* @param classProvider a provider to translate class names into {@link ClassNode class nodes}. Contains both library and main jar classes
* @param jarIndex the current jar index
*/
void acceptJar(Set<String> scope, ClassProvider classProvider, JarIndex jarIndex);
void acceptJar(Collection<String> scope, ProjectClassProvider classProvider, JarIndex jarIndex);

/**
* Whether this indexer should be run on libraries in addition to the main project being indexed.
Expand Down Expand Up @@ -69,7 +69,7 @@ static JarIndexerService fromVisitor(@Nullable EnigmaServiceContext<JarIndexerSe

return new JarIndexerService() {
@Override
public void acceptJar(Set<String> scope, ClassProvider classProvider, JarIndex jarIndex) {
public void acceptJar(Collection<String> scope, ProjectClassProvider classProvider, JarIndex jarIndex) {
for (String className : scope) {
ClassNode node = classProvider.get(className);
if (node != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.quiltmc.enigma.api.translation.representation.entry.ParentedEntry;
import org.quiltmc.enigma.util.I18n;

import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
Expand Down Expand Up @@ -72,11 +73,10 @@ public <T extends JarIndexer> T getIndex(Class<T> clazz) {

/**
* Runs every configured indexer over the provided jar.
* @param classNames the obfuscated names of each class in the jar
* @param classProvider a class provider containing all classes in the jar
* @param progress a progress listener to track index completion
*/
public void indexJar(Set<String> classNames, ClassProvider classProvider, ProgressListener progress) {
public void indexJar(Collection<String> classNames, ClassProvider classProvider, ProgressListener progress) {
// for use in processIndex
this.progress = progress;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ private static void registerEnumNamingService(EnigmaPluginContext ctx) {
final Map<Entry<?>, String> names = new HashMap<>();
final EnumFieldNameFindingVisitor visitor = new EnumFieldNameFindingVisitor(names);

ctx.registerService(JarIndexerService.TYPE, ctx1 -> JarIndexerService.fromVisitor(ctx1, visitor, "enigma:enum_initializer_indexer"));
ctx.registerService(JarIndexerService.TYPE, ctx1 -> JarIndexerService.fromVisitor(visitor, "enigma:enum_initializer_indexer"));

ctx.registerService(NameProposalService.TYPE, ctx1 -> new NameProposalService() {
@Override
Expand Down Expand Up @@ -66,7 +66,7 @@ private static void registerRecordNamingService(EnigmaPluginContext ctx) {
final Map<FieldEntry, MethodEntry> fieldToGetter = new HashMap<>();
final RecordGetterFindingVisitor visitor = new RecordGetterFindingVisitor(fieldToGetter);

ctx.registerService(JarIndexerService.TYPE, ctx1 -> JarIndexerService.fromVisitor(ctx1, visitor, "enigma:record_component_indexer"));
ctx.registerService(JarIndexerService.TYPE, ctx1 -> JarIndexerService.fromVisitor(visitor, "enigma:record_component_indexer"));
ctx.registerService(NameProposalService.TYPE, ctx1 -> new RecordComponentProposalService(fieldToGetter));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import org.quiltmc.enigma.api.analysis.index.jar.MainJarIndex;
import org.quiltmc.enigma.api.analysis.index.jar.PackageVisibilityIndex;
import org.quiltmc.enigma.api.ProgressListener;
import org.quiltmc.enigma.api.class_provider.CachingClassProvider;
import org.quiltmc.enigma.api.class_provider.JarClassProvider;
import org.quiltmc.enigma.api.class_provider.ProjectClassProvider;
import org.quiltmc.enigma.api.translation.representation.entry.ClassEntry;
import org.junit.jupiter.api.Test;

Expand All @@ -27,7 +29,7 @@ public class PackageVisibilityIndexTest {
public PackageVisibilityIndexTest() throws Exception {
JarClassProvider jcp = new JarClassProvider(JAR);
this.jarIndex = MainJarIndex.empty();
this.jarIndex.indexJar(jcp.getClassNames(), jcp, ProgressListener.createEmpty());
this.jarIndex.indexJar(new ProjectClassProvider(new CachingClassProvider(jcp), null), ProgressListener.createEmpty());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.quiltmc.enigma.api.analysis.index.jar.MainJarIndex;
import org.quiltmc.enigma.api.class_provider.CachingClassProvider;
import org.quiltmc.enigma.api.class_provider.JarClassProvider;
import org.quiltmc.enigma.api.class_provider.ProjectClassProvider;
import org.quiltmc.enigma.api.source.Decompiler;
import org.quiltmc.enigma.api.source.Decompilers;
import org.quiltmc.enigma.api.source.SourceSettings;
Expand Down Expand Up @@ -34,7 +35,7 @@ public TestInnerClasses() throws Exception {
JarClassProvider jcp = new JarClassProvider(JAR);
CachingClassProvider classProvider = new CachingClassProvider(jcp);
this.index = MainJarIndex.empty();
this.index.indexJar(jcp.getClassNames(), classProvider, ProgressListener.createEmpty());
this.index.indexJar(new ProjectClassProvider(classProvider, null), ProgressListener.createEmpty());
this.decompiler = Decompilers.CFR.create(classProvider, new SourceSettings(false, false));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.quiltmc.enigma.api.class_provider.CachingClassProvider;
import org.quiltmc.enigma.api.class_provider.JarClassProvider;
import org.quiltmc.enigma.api.class_provider.ObfuscationFixClassProvider;
import org.quiltmc.enigma.api.class_provider.ProjectClassProvider;
import org.quiltmc.enigma.api.service.DecompilerService;
import org.quiltmc.enigma.api.source.Decompilers;
import org.quiltmc.enigma.api.translation.representation.entry.ClassEntry;
Expand Down Expand Up @@ -40,7 +41,7 @@ public TestJarIndexBridgeMethods() throws Exception {
JarClassProvider jcp = new JarClassProvider(JAR);
this.classProvider = new CachingClassProvider(jcp);
this.index = MainJarIndex.empty();
this.index.indexJar(jcp.getClassNames(), this.classProvider, ProgressListener.createEmpty());
this.index.indexJar(new ProjectClassProvider(this.classProvider, null), ProgressListener.createEmpty());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.quiltmc.enigma.api.analysis.index.jar.ReferenceIndex;
import org.quiltmc.enigma.api.class_provider.CachingClassProvider;
import org.quiltmc.enigma.api.class_provider.JarClassProvider;
import org.quiltmc.enigma.api.class_provider.ProjectClassProvider;
import org.quiltmc.enigma.api.translation.representation.entry.ClassEntry;
import org.quiltmc.enigma.api.translation.representation.entry.MethodDefEntry;
import org.quiltmc.enigma.api.translation.representation.entry.MethodEntry;
Expand All @@ -34,7 +35,7 @@ public class TestJarIndexConstructorReferences {
public TestJarIndexConstructorReferences() throws Exception {
JarClassProvider jcp = new JarClassProvider(JAR);
this.index = MainJarIndex.empty();
this.index.indexJar(jcp.getClassNames(), new CachingClassProvider(jcp), ProgressListener.createEmpty());
this.index.indexJar(new ProjectClassProvider(new CachingClassProvider(jcp), null), ProgressListener.createEmpty());
}

@Test
Expand Down
Loading

0 comments on commit d2e9071

Please sign in to comment.