diff --git a/compiler/src/main/java/motif/compiler/Processor.kt b/compiler/src/main/java/motif/compiler/Processor.kt index 1af68ec8..4c3f3cb4 100644 --- a/compiler/src/main/java/motif/compiler/Processor.kt +++ b/compiler/src/main/java/motif/compiler/Processor.kt @@ -15,57 +15,55 @@ */ package motif.compiler +import com.google.auto.common.BasicAnnotationProcessor +import com.google.common.collect.SetMultimap import motif.Scope +import motif.ast.compiler.CompilerType import motif.compiler.codegen.Generator import motif.compiler.errors.ErrorHandler -import motif.ast.compiler.CompilerType import motif.models.errors.MotifErrors import motif.models.graph.GraphFactory -import javax.annotation.processing.AbstractProcessor -import javax.annotation.processing.RoundEnvironment import javax.lang.model.SourceVersion -import javax.lang.model.element.TypeElement +import javax.lang.model.element.Element import javax.tools.Diagnostic -class Processor : AbstractProcessor() { +class Processor : BasicAnnotationProcessor() { // For testing only. var errors: MotifErrors? = null - private val hasErrors: Boolean - get() = !(errors?.isEmpty() ?: true) - override fun getSupportedSourceVersion(): SourceVersion { return SourceVersion.latestSupported() } - override fun getSupportedAnnotationTypes(): Set { - return setOf(Scope::class.java.name) + override fun initSteps(): Iterable { + return listOf(Step()) } - override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { - if (roundEnv.processingOver() || hasErrors) { - return true + private inner class Step : BasicAnnotationProcessor.ProcessingStep { + + override fun annotations(): Set> { + return setOf(motif.Scope::class.java) } - process(roundEnv) - return true - } - private fun process(roundEnv: RoundEnvironment) { - val scopeTypes = roundEnv.getElementsAnnotatedWith(Scope::class.java) - .map { CompilerType(processingEnv, it.asType()) } - .toSet() - val graph = GraphFactory.create(scopeTypes) - val errors = graph.errors - this.errors = errors + override fun process(elementsByAnnotation: SetMultimap, Element>): Set { + val scopeTypes = elementsByAnnotation[Scope::class.java] + .map { CompilerType(processingEnv, it.asType()) } + .toSet() + val graph = GraphFactory.create(scopeTypes) + val errors = graph.errors + this@Processor.errors = errors - if (errors.isEmpty()) { - Generator(processingEnv, graph).generate() - } else { - errors.forEach { error -> - val errorMessage = ErrorHandler.handle(error) - processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, "\n${errorMessage.message}\n", errorMessage.element) + if (errors.isEmpty()) { + Generator(processingEnv, graph).generate() + } else { + errors.forEach { error -> + val errorMessage = ErrorHandler.handle(error) + processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, "\n${errorMessage.message}\n", errorMessage.element) + } } + + return emptySet() } } } \ No newline at end of file diff --git a/compiler2/src/main/kotlin/motif/compiler/Processor.kt b/compiler2/src/main/kotlin/motif/compiler/Processor.kt index 8a58d81c..bd0e5d53 100644 --- a/compiler2/src/main/kotlin/motif/compiler/Processor.kt +++ b/compiler2/src/main/kotlin/motif/compiler/Processor.kt @@ -15,18 +15,20 @@ */ package motif.compiler +import com.google.auto.common.BasicAnnotationProcessor +import com.google.common.collect.SetMultimap import com.squareup.javapoet.JavaFile +import motif.Scope import motif.ast.compiler.CompilerClass import motif.core.ResolvedGraph import motif.errormessage.ErrorMessage -import javax.annotation.processing.AbstractProcessor -import javax.annotation.processing.RoundEnvironment import javax.lang.model.SourceVersion -import javax.lang.model.element.TypeElement +import javax.lang.model.element.Element import javax.lang.model.type.DeclaredType +import javax.lang.model.type.TypeKind import javax.tools.Diagnostic -class Processor : AbstractProcessor() { +class Processor : BasicAnnotationProcessor() { lateinit var graph: ResolvedGraph @@ -34,38 +36,40 @@ class Processor : AbstractProcessor() { return SourceVersion.latestSupported() } - override fun getSupportedAnnotationTypes(): Set { - return setOf(motif.Scope::class.java.name) + override fun initSteps(): Iterable { + return listOf(Step()) } - override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { - if (roundEnv.processingOver()) { - return true - } - process(roundEnv) - return true - } + private inner class Step : ProcessingStep { - private fun process(roundEnv: RoundEnvironment) { - val initialScopeClasses = roundEnv.getElementsAnnotatedWith(motif.Scope::class.java) - .map { CompilerClass(processingEnv, it.asType() as DeclaredType) } - if (initialScopeClasses.isEmpty()) { - return + override fun annotations(): Set> { + return setOf(motif.Scope::class.java) } - this.graph = ResolvedGraph.create(initialScopeClasses) + override fun process(elementsByAnnotation: SetMultimap, Element>): Set { + val scopeElements = elementsByAnnotation[Scope::class.java] + val initialScopeClasses = scopeElements + .map { CompilerClass(processingEnv, it.asType() as DeclaredType) } + if (initialScopeClasses.isEmpty()) { + return emptySet() + } - if (graph.errors.isNotEmpty()) { - val errorMessage = ErrorMessage.toString(graph) - processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, errorMessage) - return - } + this@Processor.graph = ResolvedGraph.create(initialScopeClasses) + + if (graph.errors.isNotEmpty()) { + val errorMessage = ErrorMessage.toString(graph) + processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, errorMessage) + return emptySet() + } + + val scopeImpls = ScopeImpl.create(processingEnv, graph) - val scopeImpls = ScopeImpl.create(processingEnv, graph) + scopeImpls.forEach { scopeImpl -> + val spec = scopeImpl.spec ?: return@forEach + JavaFile.builder(scopeImpl.packageName, spec).build().writeTo(processingEnv.filer) + } - scopeImpls.forEach { scopeImpl -> - val spec = scopeImpl.spec ?: return@forEach - JavaFile.builder(scopeImpl.packageName, spec).build().writeTo(processingEnv.filer) + return emptySet() } } -} \ No newline at end of file +} diff --git a/tests/compiler/src/main/java/motif/stubcompiler/StubProcessor.kt b/tests/compiler/src/main/java/motif/stubcompiler/StubProcessor.kt index 97762543..d0a9e031 100644 --- a/tests/compiler/src/main/java/motif/stubcompiler/StubProcessor.kt +++ b/tests/compiler/src/main/java/motif/stubcompiler/StubProcessor.kt @@ -29,6 +29,7 @@ import javax.annotation.processing.ProcessingEnvironment import javax.annotation.processing.RoundEnvironment import javax.lang.model.SourceVersion import javax.lang.model.element.ElementKind +import javax.lang.model.element.Modifier import javax.lang.model.element.TypeElement import javax.lang.model.type.DeclaredType @@ -63,6 +64,7 @@ class StubProcessor : AbstractProcessor() { } val builder = TypeSpec.classBuilder(scopeImplClassName) .addMethod(MethodSpec.constructorBuilder().build()) + .addType(TypeSpec.interfaceBuilder("Dependencies").build()) if (scopeType.asElement().kind == ElementKind.INTERFACE) { builder.addSuperinterface(scopeClassName) diff --git a/tests/src/main/java/testcases/T056_deferred_rounds/Child.java b/tests/src/main/java/testcases/T056_deferred_rounds/Child.java new file mode 100644 index 00000000..a218bdf6 --- /dev/null +++ b/tests/src/main/java/testcases/T056_deferred_rounds/Child.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018 Uber Technologies, Inc. + * + * 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 testcases.T056_deferred_rounds; + +@motif.Scope +public interface Child { + + String string(); +} diff --git a/tests/src/main/java/testcases/T056_deferred_rounds/Scope.java b/tests/src/main/java/testcases/T056_deferred_rounds/Scope.java new file mode 100644 index 00000000..38dbd8ee --- /dev/null +++ b/tests/src/main/java/testcases/T056_deferred_rounds/Scope.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018 Uber Technologies, Inc. + * + * 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 testcases.T056_deferred_rounds; + +@motif.Scope +public interface Scope extends ChildImpl.Dependencies { + + @motif.Objects + class Objects { + + String string() { + return "s"; + } + } +} diff --git a/tests/src/main/java/testcases/T056_deferred_rounds/Test.java b/tests/src/main/java/testcases/T056_deferred_rounds/Test.java new file mode 100644 index 00000000..49f4d3d1 --- /dev/null +++ b/tests/src/main/java/testcases/T056_deferred_rounds/Test.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018 Uber Technologies, Inc. + * + * 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 testcases.T056_deferred_rounds; + +public class Test { + + public static void run() { + new ScopeImpl(); + } +}