<commit_before>package de.is24.deadcode4j.analyzer.javassist;

import com.google.common.base.Optional;
import de.is24.deadcode4j.CodeContext;
import de.is24.deadcode4j.Repository;
import javassist.ClassPool;
import javassist.NotFoundException;

import javax.annotation.Nonnull;
import java.io.File;

import static com.google.common.base.Optional.absent;
import static com.google.common.base.Optional.of;

public final class ClassPoolAccessor {
    @Nonnull
    private final ClassPool classPool;

    public ClassPoolAccessor(@Nonnull CodeContext codeContext) {
        this.classPool = createClassPool(codeContext);
    }

    @Nonnull
    public static ClassPoolAccessor classPoolAccessorFor(@Nonnull CodeContext codeContext) {
        ClassPoolAccessor classPoolAccessor = (ClassPoolAccessor) codeContext.getCache().get(ClassPoolAccessor.class);
        if (classPoolAccessor == null) {
            classPoolAccessor = new ClassPoolAccessor(codeContext);
            codeContext.getCache().put(ClassPoolAccessor.class, classPoolAccessor);
        }
        return classPoolAccessor;
    }

    /**
     * Returns the <code>ClassPool</code> used for examining classes.
     *
     * @since 1.6
     */
    @Nonnull
    public final ClassPool getClassPool() {
        return this.classPool;
    }

    /**
     * Returns the "resolved" class name for the given qualifier.
     * "Resolved" in this case means that if the qualifier refers to an existing class, the class'
     * {@link java.lang.ClassLoader binary name} is returned.
     *
     * @since 1.6
     */
    @Nonnull
    public Optional<String> resolveClass(@Nonnull CharSequence qualifier) {
        String qualifierString = qualifier.toString();
        for (; ; ) {
            if (this.classPool.getOrNull(qualifierString) != null) {
                return of(qualifierString);
            }
            int dotIndex = qualifierString.lastIndexOf('.');
            if (dotIndex < 0) {
                return absent();
            }
            qualifierString = qualifierString.substring(0, dotIndex) + "$" + qualifierString.substring(dotIndex + 1);
        }
    }

    @Nonnull
    private ClassPool createClassPool(CodeContext codeContext) {
        ClassPool classPool = new ClassPool(true);
        try {
            Repository outputRepository = codeContext.getModule().getOutputRepository();
            if (outputRepository != null) {
                classPool.appendClassPath(outputRepository.getDirectory().getAbsolutePath());
            }
            for (File file : codeContext.getModule().getClassPath()) {
                classPool.appendClassPath(file.getAbsolutePath());
            }
        } catch (NotFoundException e) {
            throw new RuntimeException("Failed to set up ClassPool!", e);
        }
        return classPool;
    }

}<commit_msg>cache class resolving<commit_after>package de.is24.deadcode4j.analyzer.javassist;

import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import de.is24.deadcode4j.CodeContext;
import de.is24.deadcode4j.Repository;
import javassist.ClassPool;
import javassist.NotFoundException;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;

import static com.google.common.base.Optional.absent;
import static com.google.common.base.Optional.of;

public final class ClassPoolAccessor {
    @Nonnull
    private final ClassPool classPool;
    @Nonnull
    private final LoadingCache<String, Optional<String>> classResolver;

    public ClassPoolAccessor(@Nonnull CodeContext codeContext) {
        this.classPool = createClassPool(codeContext);
        this.classResolver = createResolverCache();
    }

    @Nonnull
    public static ClassPoolAccessor classPoolAccessorFor(@Nonnull CodeContext codeContext) {
        ClassPoolAccessor classPoolAccessor = (ClassPoolAccessor) codeContext.getCache().get(ClassPoolAccessor.class);
        if (classPoolAccessor == null) {
            classPoolAccessor = new ClassPoolAccessor(codeContext);
            codeContext.getCache().put(ClassPoolAccessor.class, classPoolAccessor);
        }
        return classPoolAccessor;
    }

    /**
     * Returns the <code>ClassPool</code> used for examining classes.
     *
     * @since 1.6
     */
    @Nonnull
    public final ClassPool getClassPool() {
        return this.classPool;
    }

    /**
     * Returns the "resolved" class name for the given qualifier.
     * "Resolved" in this case means that if the qualifier refers to an existing class, the class'
     * {@link java.lang.ClassLoader binary name} is returned.
     *
     * @since 1.6
     */
    @Nonnull
    public Optional<String> resolveClass(@Nonnull CharSequence qualifier) {
        return classResolver.getUnchecked(qualifier.toString());
    }

    @Nonnull
    private ClassPool createClassPool(CodeContext codeContext) {
        ClassPool classPool = new ClassPool(true);
        try {
            Repository outputRepository = codeContext.getModule().getOutputRepository();
            if (outputRepository != null) {
                classPool.appendClassPath(outputRepository.getDirectory().getAbsolutePath());
            }
            for (File file : codeContext.getModule().getClassPath()) {
                classPool.appendClassPath(file.getAbsolutePath());
            }
        } catch (NotFoundException e) {
            throw new RuntimeException("Failed to set up ClassPool!", e);
        }
        return classPool;
    }

    private LoadingCache<String, Optional<String>> createResolverCache() {
        return CacheBuilder.newBuilder().concurrencyLevel(1).recordStats().build(CacheLoader.from(new Function<String, Optional<String>>() {
            @Nullable
            @Override
            public Optional<String> apply(@Nullable String input) {
                if (input == null) {
                    return absent();
                }
                for (; ; ) {
                    if (classPool.getOrNull(input) != null) {
                        return of(input);
                    }
                    int dotIndex = input.lastIndexOf('.');
                    if (dotIndex < 0) {
                        return absent();
                    }
                    input = input.substring(0, dotIndex) + "$" + input.substring(dotIndex + 1);
                }
            }
        }));
    }

}
{'fraction_non_alphanumeric': 0.09643734643734644, 'fraction_numerical': 0.005067567567567568, 'mean_word_length': 2.5473856209150325, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2895027', 'n_tokens_mistral': 1735, 'n_tokens_neox': 1681, 'n_words': 379}