<commit_before>package com.matthewtamlin.spyglass.processor.core;

import com.matthewtamlin.spyglass.processor.code_generation.AndroidClassNames;
import com.matthewtamlin.spyglass.processor.code_generation.CallerDef;
import com.matthewtamlin.spyglass.processor.code_generation.CallerGenerator;
import com.matthewtamlin.spyglass.processor.grouper.TypeElementWrapper;
import com.matthewtamlin.spyglass.processor.validation.ValidationException;
import com.matthewtamlin.spyglass.processor.validation.Validator;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;

import static com.matthewtamlin.spyglass.processor.grouper.Grouper.groupByEnclosingClass;
import static javax.tools.Diagnostic.Kind.ERROR;

public class MainProcessor extends AbstractProcessor {
	private static final Set<Class<? extends Annotation>> SUPPORTED_ANNOTATIONS;

	private Messager messager;

	private Filer filer;

	private Elements elementUtil;

	private CallerGenerator callerGenerator;

	static {
		final Set<Class<? extends Annotation>> intermediateSet = new HashSet<>();

		intermediateSet.addAll(AnnotationRegistry.CALL_HANDLER_ANNOTATIONS);
		intermediateSet.addAll(AnnotationRegistry.VALUE_HANDLER_ANNOTATIONS);
		intermediateSet.addAll(AnnotationRegistry.DEFAULT_ANNOTATIONS);

		SUPPORTED_ANNOTATIONS = Collections.unmodifiableSet(intermediateSet);
	}

	@Override
	public synchronized void init(final ProcessingEnvironment processingEnvironment) {
		super.init(processingEnvironment);

		callerGenerator = new CallerGenerator(processingEnvironment.getElementUtils());

		messager = processingEnvironment.getMessager();
		filer = processingEnvironment.getFiler();
		elementUtil = processingEnvironment.getElementUtils();

		createFile(CallerDef.getJavaFile(), "Could not create Caller class file.");
	}

	@Override
	public Set<String> getSupportedAnnotationTypes() {
		final Set<String> supportedTypes = new HashSet<>();

		for (Class<? extends Annotation> clazz : SUPPORTED_ANNOTATIONS) {
			supportedTypes.add(clazz.getCanonicalName());
		}

		return supportedTypes;
	}

	@Override
	public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
		final Set<ExecutableElement> allElements = findSupportedElements(roundEnv);
		validateElements(allElements);
		createCompanions(allElements);

		return false;
	}

	private Set<ExecutableElement> findSupportedElements(final RoundEnvironment roundEnv) {
		final Set<ExecutableElement> supportedElements = new HashSet<>();

		for (final Class<? extends Annotation> annoType : SUPPORTED_ANNOTATIONS) {
			for (final Element foundElement : roundEnv.getElementsAnnotatedWith(annoType)) {
				// All elements should be executable elements
				supportedElements.add((ExecutableElement) foundElement);
			}
		}

		return supportedElements;
	}

	private void validateElements(final Set<? extends Element> elements) {
		for (final Element element : elements) {
			try {
				Validator.validateElement(element);

			} catch (final ValidationException validationException) {
				messager.printMessage(ERROR, validationException.getMessage(), element);

			} catch (final Exception exception) {
				messager.printMessage(ERROR, "Spyglass validation failure.", element);
			}
		}
	}

	private void createCompanions(final Set<ExecutableElement> elements) {
		final Map<TypeElementWrapper, Set<ExecutableElement>> sortedElements = groupByEnclosingClass(elements);

		for (final TypeElementWrapper targetClass : sortedElements.keySet()) {
			final CodeBlock.Builder methodBody = CodeBlock.builder();

			for (final ExecutableElement method : sortedElements.get(targetClass)) {
				final TypeSpec anonymousCaller = callerGenerator.generateCaller(method);

				methodBody.addStatement("$L.call(target, context, attrs)", anonymousCaller);
				methodBody.add("\n");
			}

			final MethodSpec activateCallers = MethodSpec
					.methodBuilder("activateCallers")
					.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
					.returns(void.class)
					.addParameter(TypeName.get(targetClass.unwrap().asType()), "target")
					.addParameter(AndroidClassNames.CONTEXT, "context")
					.addParameter(AndroidClassNames.TYPED_ARRAY, "attrs")
					.addCode(methodBody.build())
					.build();

			final TypeSpec companionClass = TypeSpec
					.classBuilder(targetClass.unwrap().getSimpleName() + "_SpyglassCompanion")
					.addMethod(activateCallers)
					.build();

			final JavaFile companionFile = JavaFile
					.builder(
							elementUtil.getPackageOf(targetClass.unwrap()).getQualifiedName().toString(),
							companionClass)
					.addFileComment("Generated by the Spyglass framework. Do not modify!")
					.indent("\t")
					.build();

			createFile(
					companionFile,
					"Could not create companion file for class " + targetClass.unwrap().getSimpleName() + ".");
		}
	}

	private void createFile(final JavaFile file, final String errorMessage) {
		try {
			file.writeTo(filer);
		} catch (final IOException e) {
			messager.printMessage(ERROR, errorMessage);
		}
	}
}<commit_msg>Moved companion class suffix to static variable<commit_after>package com.matthewtamlin.spyglass.processor.core;

import com.matthewtamlin.spyglass.processor.code_generation.AndroidClassNames;
import com.matthewtamlin.spyglass.processor.code_generation.CallerDef;
import com.matthewtamlin.spyglass.processor.code_generation.CallerGenerator;
import com.matthewtamlin.spyglass.processor.grouper.TypeElementWrapper;
import com.matthewtamlin.spyglass.processor.validation.ValidationException;
import com.matthewtamlin.spyglass.processor.validation.Validator;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;

import static com.matthewtamlin.spyglass.processor.grouper.Grouper.groupByEnclosingClass;
import static javax.tools.Diagnostic.Kind.ERROR;

public class MainProcessor extends AbstractProcessor {
	private static final String COMPANION_CLASS_NAME_SUFFIX = "_SpyglassCompanion";

	private static final Set<Class<? extends Annotation>> SUPPORTED_ANNOTATIONS;

	private Messager messager;

	private Filer filer;

	private Elements elementUtil;

	private CallerGenerator callerGenerator;

	static {
		final Set<Class<? extends Annotation>> intermediateSet = new HashSet<>();

		intermediateSet.addAll(AnnotationRegistry.CALL_HANDLER_ANNOTATIONS);
		intermediateSet.addAll(AnnotationRegistry.VALUE_HANDLER_ANNOTATIONS);
		intermediateSet.addAll(AnnotationRegistry.DEFAULT_ANNOTATIONS);

		SUPPORTED_ANNOTATIONS = Collections.unmodifiableSet(intermediateSet);
	}

	@Override
	public synchronized void init(final ProcessingEnvironment processingEnvironment) {
		super.init(processingEnvironment);

		callerGenerator = new CallerGenerator(processingEnvironment.getElementUtils());

		messager = processingEnvironment.getMessager();
		filer = processingEnvironment.getFiler();
		elementUtil = processingEnvironment.getElementUtils();

		createFile(CallerDef.getJavaFile(), "Could not create Caller class file.");
	}

	@Override
	public Set<String> getSupportedAnnotationTypes() {
		final Set<String> supportedTypes = new HashSet<>();

		for (Class<? extends Annotation> clazz : SUPPORTED_ANNOTATIONS) {
			supportedTypes.add(clazz.getCanonicalName());
		}

		return supportedTypes;
	}

	@Override
	public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
		final Set<ExecutableElement> allElements = findSupportedElements(roundEnv);
		validateElements(allElements);
		createCompanions(allElements);

		return false;
	}

	private Set<ExecutableElement> findSupportedElements(final RoundEnvironment roundEnv) {
		final Set<ExecutableElement> supportedElements = new HashSet<>();

		for (final Class<? extends Annotation> annoType : SUPPORTED_ANNOTATIONS) {
			for (final Element foundElement : roundEnv.getElementsAnnotatedWith(annoType)) {
				// All elements should be executable elements
				supportedElements.add((ExecutableElement) foundElement);
			}
		}

		return supportedElements;
	}

	private void validateElements(final Set<? extends Element> elements) {
		for (final Element element : elements) {
			try {
				Validator.validateElement(element);

			} catch (final ValidationException validationException) {
				messager.printMessage(ERROR, validationException.getMessage(), element);

			} catch (final Exception exception) {
				messager.printMessage(ERROR, "Spyglass validation failure.", element);
			}
		}
	}

	private void createCompanions(final Set<ExecutableElement> elements) {
		final Map<TypeElementWrapper, Set<ExecutableElement>> sortedElements = groupByEnclosingClass(elements);

		for (final TypeElementWrapper targetClass : sortedElements.keySet()) {
			final CodeBlock.Builder methodBody = CodeBlock.builder();

			for (final ExecutableElement method : sortedElements.get(targetClass)) {
				final TypeSpec anonymousCaller = callerGenerator.generateCaller(method);

				methodBody.addStatement("$L.call(target, context, attrs)", anonymousCaller);
				methodBody.add("\n");
			}

			final MethodSpec activateCallers = MethodSpec
					.methodBuilder("activateCallers")
					.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
					.returns(void.class)
					.addParameter(TypeName.get(targetClass.unwrap().asType()), "target")
					.addParameter(AndroidClassNames.CONTEXT, "context")
					.addParameter(AndroidClassNames.TYPED_ARRAY, "attrs")
					.addCode(methodBody.build())
					.build();

			final TypeSpec companionClass = TypeSpec
					.classBuilder(targetClass.unwrap().getSimpleName() + COMPANION_CLASS_NAME_SUFFIX)
					.addMethod(activateCallers)
					.build();

			final JavaFile companionFile = JavaFile
					.builder(
							elementUtil.getPackageOf(targetClass.unwrap()).getQualifiedName().toString(),
							companionClass)
					.addFileComment("Generated by the Spyglass framework. Do not modify!")
					.indent("\t")
					.build();

			createFile(
					companionFile,
					"Could not create companion file for class " + targetClass.unwrap().getSimpleName() + ".");
		}
	}

	private void createFile(final JavaFile file, final String errorMessage) {
		try {
			file.writeTo(filer);
		} catch (final IOException e) {
			messager.printMessage(ERROR, errorMessage);
		}
	}
}
{'fraction_non_alphanumeric': 0.0972163105473738, 'fraction_numerical': 0.0, 'mean_word_length': 5.7131428571428575, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 41, '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': '423099', 'n_tokens_mistral': 3713, 'n_tokens_neox': 3244, 'n_words': 656}