<commit_before>/*
 *    Copyright (c) 2008-2011 <NAME>
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */
package org.mutabilitydetector;

import static java.lang.String.format;
import static org.mutabilitydetector.CheckerRunner.ExceptionPolicy.FAIL_FAST;

import java.io.IOException;
import java.io.InputStream;

import org.mutabilitydetector.AnalysisErrorReporter.AnalysisError;
import org.mutabilitydetector.checkers.AsmMutabilityChecker;
import org.mutabilitydetector.checkers.AsmMutabilityChecker.CheckerResult;
import org.mutabilitydetector.locations.Dotted;
import org.objectweb.asm.ClassReader;

import com.google.classpath.ClassPath;
import com.google.classpath.ClassPathFactory;

public final class CheckerRunner {

    private final ClassPath classpath;
    private final UnhandledExceptionBuilder unhandledExceptionBuilder;
    private ExceptionPolicy exceptionPolicy;

    private CheckerRunner(ClassPath classpath, UnhandledExceptionBuilder unhandledExceptionBuilder, ExceptionPolicy exceptionPolicy) {
        this.classpath = classpath;
        this.unhandledExceptionBuilder = unhandledExceptionBuilder;
        this.exceptionPolicy = exceptionPolicy;
    }

    public static CheckerRunner createWithClasspath(ClassPath classpath, ExceptionPolicy exceptionPolicy) {
        return new CheckerRunner(classpath, new UnhandledExceptionBuilder(), exceptionPolicy);
    }

    public static CheckerRunner createWithCurrentClasspath(ExceptionPolicy exceptionPolicy) {
        return createWithClasspath(new ClassPathFactory().createFromJVM(), exceptionPolicy);
    }
    
    public static enum ExceptionPolicy {
        FAIL_FAST, CARRY_ON
    }

    public CheckerResult run(AsmMutabilityChecker checker, Dotted className, AnalysisErrorReporter errorReporter, Iterable<AnalysisResult> resultsSoFar) {
        try {
            try {
                ClassReader cr = new ClassReader(className.asString());
                cr.accept(checker, 0);
            } catch (NoClassDefFoundError e) {
                analyseAsStream(checker, className.asString());
            } catch (IOException e) {
                analyseAsStream(checker, className.asString());
            }
        } catch (Throwable e) {
            attemptRecovery(checker, className, errorReporter, resultsSoFar, e);
        }
        return checker.checkerResult();
    }

    private void attemptRecovery(AsmMutabilityChecker checker,
                                 Dotted className,
                                 AnalysisErrorReporter errorReporter,
                                 Iterable<AnalysisResult> resultsSoFar,
                                 Throwable e) {

        if (!isRecoverable(e) || exceptionPolicy == FAIL_FAST) {
            throw unhandledExceptionBuilder.unhandledException(e, resultsSoFar, checker, className);
        } else {
            handleException(errorReporter, checker, className.asString(), e);
        }
    }
    
    private boolean isRecoverable(Throwable e) {
        Throwable cause = underlyingCause(e);
        return (cause instanceof Exception) || (cause instanceof LinkageError);
    }

    private Throwable underlyingCause(Throwable e) {
        Throwable rootCause = e;
        while (rootCause.getCause() != null) {
            rootCause = rootCause.getCause();
        }
        return rootCause;
    }

    private void analyseAsStream(AsmMutabilityChecker checker, String dottedClassPath) throws IOException {
        String slashedClassPath = dottedClassPath.replace(".", "/").concat(".class");
        InputStream classStream = classpath.getResourceAsStream(slashedClassPath);
        ClassReader cr = new ClassReader(classStream);<commit_msg>Attempt analysing as a stream first, class second.<commit_after>/*
 *    Copyright (c) 2008-2011 <NAME>
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */
package org.mutabilitydetector;

import static java.lang.String.format;
import static org.mutabilitydetector.CheckerRunner.ExceptionPolicy.FAIL_FAST;

import java.io.IOException;
import java.io.InputStream;

import org.mutabilitydetector.AnalysisErrorReporter.AnalysisError;
import org.mutabilitydetector.checkers.AsmMutabilityChecker;
import org.mutabilitydetector.checkers.AsmMutabilityChecker.CheckerResult;
import org.mutabilitydetector.locations.Dotted;
import org.objectweb.asm.ClassReader;

import com.google.classpath.ClassPath;
import com.google.classpath.ClassPathFactory;

public final class CheckerRunner {

    private final ClassPath classpath;
    private final UnhandledExceptionBuilder unhandledExceptionBuilder;
    private ExceptionPolicy exceptionPolicy;

    private CheckerRunner(ClassPath classpath, UnhandledExceptionBuilder unhandledExceptionBuilder, ExceptionPolicy exceptionPolicy) {
        this.classpath = classpath;
        this.unhandledExceptionBuilder = unhandledExceptionBuilder;
        this.exceptionPolicy = exceptionPolicy;
    }

    public static CheckerRunner createWithClasspath(ClassPath classpath, ExceptionPolicy exceptionPolicy) {
        return new CheckerRunner(classpath, new UnhandledExceptionBuilder(), exceptionPolicy);
    }

    public static CheckerRunner createWithCurrentClasspath(ExceptionPolicy exceptionPolicy) {
        return createWithClasspath(new ClassPathFactory().createFromJVM(), exceptionPolicy);
    }
    
    public static enum ExceptionPolicy {
        FAIL_FAST, CARRY_ON
    }

    public CheckerResult run(AsmMutabilityChecker checker, Dotted className, AnalysisErrorReporter errorReporter, Iterable<AnalysisResult> resultsSoFar) {
        try {
            try {
                analyseAsStream(checker, className.asString());
            } catch (Exception e) {
                analyseFromDefaultClassLoader(checker, className.asString());
            }
        } catch (Throwable e) {
            attemptRecovery(checker, className, errorReporter, resultsSoFar, e);
        }
        return checker.checkerResult();
    }


    private void attemptRecovery(AsmMutabilityChecker checker,
                                 Dotted className,
                                 AnalysisErrorReporter errorReporter,
                                 Iterable<AnalysisResult> resultsSoFar,
                                 Throwable e) {

        if (!isRecoverable(e) || exceptionPolicy == FAIL_FAST) {
            throw unhandledExceptionBuilder.unhandledException(e, resultsSoFar, checker, className);
        } else {
            handleException(errorReporter, checker, className.asString(), e);
        }
    }
    
    private boolean isRecoverable(Throwable e) {
        Throwable cause = underlyingCause(e);
        return (cause instanceof Exception) || (cause instanceof LinkageError);
    }

    private Throwable underlyingCause(Throwable e) {
        Throwable rootCause = e;
        while (rootCause.getCause() != null) {
            rootCause = rootCause.getCause();
        }
        return rootCause;
    }

    private void analyseFromDefaultClassLoader(AsmMutabilityChecker checker, String className) throws IOException {
        ClassReader cr = new ClassReader(className);
        cr.accept(checker, 0);
    }

    private void analyseAsStream(AsmMutabilityChecker checker, String dottedClassPath) throws IOException {
        String slashedClassPath = dottedClassPath.replace(".", "/").concat(".class");
        InputStream classStream = classpath.getResourceAsStream(slashedClassPath);
        ClassReader cr = new ClassReader(classStream);
{'fraction_non_alphanumeric': 0.07282519611286735, 'fraction_numerical': 0.0030441400304414, 'mean_word_length': 3.205809945839488, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '685729', 'n_tokens_mistral': 2201, 'n_tokens_neox': 2133, 'n_words': 563}