From 965e8932814ba79804ff8977ad346837df8c9c35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89amonn=20McManus?= Date: Wed, 10 May 2023 14:40:36 -0700 Subject: [PATCH] Enable AutoService verifications by default. Previously AutoService only verified that the annotated class actually implemented the service interface _if_ you compiled with `-Averify=true`. There doesn't seem to have been a good reason for that, so now AutoService verifies _unless_ you specify `-Averify=false`. As an example, this will no longer compile: ```java @AutoService(SomeService.class) public class SomeServiceImpl {} // does not implement SomeService ``` Also add the ability to use `@SuppressWarnings("AutoService")` to disable this and other future verifications. RELNOTES=AutoService now verifies by default that the annotated class does indeed implement the interface in `@AutoServce`. Previously this only happened when compiling with `-Averify=true`. The verification can be disabled either by compiling with `-Averify=false` or by adding `@SuppressWarnings("AutoService")` to the annotated class. PiperOrigin-RevId: 531009313 --- .../processor/AutoServiceProcessor.java | 10 +-- .../processor/AutoServiceProcessorTest.java | 63 ++++++++++++++++++- .../test/resources/test/DoesNotImplement.java | 22 +++++++ .../test/DoesNotImplementSuppressed.java | 23 +++++++ 4 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 service/processor/src/test/resources/test/DoesNotImplement.java create mode 100644 service/processor/src/test/resources/test/DoesNotImplementSuppressed.java diff --git a/service/processor/src/main/java/com/google/auto/service/processor/AutoServiceProcessor.java b/service/processor/src/main/java/com/google/auto/service/processor/AutoServiceProcessor.java index 85a24cb455..06e391e98a 100644 --- a/service/processor/src/main/java/com/google/auto/service/processor/AutoServiceProcessor.java +++ b/service/processor/src/main/java/com/google/auto/service/processor/AutoServiceProcessor.java @@ -228,8 +228,8 @@ private boolean checkImplementer( TypeElement providerType, AnnotationMirror annotationMirror) { - String verify = processingEnv.getOptions().get("verify"); - if (verify == null || !Boolean.parseBoolean(verify)) { + if (!Boolean.parseBoolean(processingEnv.getOptions().getOrDefault("verify", "true")) + || suppresses(providerImplementer, "AutoService")) { return true; } @@ -246,7 +246,7 @@ private boolean checkImplementer( // So we allow that with a warning, which can be suppressed with @SuppressWarnings("rawtypes"). // See https://github.com/google/auto/issues/870. if (types.isSubtype(providerImplementer.asType(), types.erasure(providerType.asType()))) { - if (!rawTypesSuppressed(providerImplementer)) { + if (!suppresses(providerImplementer, "rawtypes")) { warning( "Service provider " + providerType @@ -261,10 +261,10 @@ private boolean checkImplementer( return false; } - private static boolean rawTypesSuppressed(Element element) { + private static boolean suppresses(Element element, String warning) { for (; element != null; element = element.getEnclosingElement()) { SuppressWarnings suppress = element.getAnnotation(SuppressWarnings.class); - if (suppress != null && Arrays.asList(suppress.value()).contains("rawtypes")) { + if (suppress != null && Arrays.asList(suppress.value()).contains(warning)) { return true; } } diff --git a/service/processor/src/test/java/com/google/auto/service/processor/AutoServiceProcessorTest.java b/service/processor/src/test/java/com/google/auto/service/processor/AutoServiceProcessorTest.java index 7a176dd93c..560aa99570 100644 --- a/service/processor/src/test/java/com/google/auto/service/processor/AutoServiceProcessorTest.java +++ b/service/processor/src/test/java/com/google/auto/service/processor/AutoServiceProcessorTest.java @@ -16,8 +16,8 @@ package com.google.auto.service.processor; import static com.google.auto.service.processor.AutoServiceProcessor.MISSING_SERVICES_ERROR; -import static com.google.testing.compile.CompilationSubject.assertThat; import static com.google.common.truth.Truth.assertThat; +import static com.google.testing.compile.CompilationSubject.assertThat; import com.google.common.io.Resources; import com.google.testing.compile.Compilation; @@ -87,11 +87,55 @@ public void badMultiService() { assertThat(compilation).hadErrorContaining(MISSING_SERVICES_ERROR); } + @Test + public void doesNotImplement_failsByDefault() { + Compilation compilation = + Compiler.javac() + .withProcessors(new AutoServiceProcessor()) + .compile( + JavaFileObjects.forResource("test/DoesNotImplement.java")); + assertThat(compilation).failed(); + assertThat(compilation) + .hadErrorContaining("test.DoesNotImplement does not implement test.SomeService"); + } + + @Test + public void doesNotImplement_succeedsWithVerifyFalse() { + Compilation compilation = + Compiler.javac() + .withProcessors(new AutoServiceProcessor()) + .withOptions("-Averify=false") + .compile( + JavaFileObjects.forResource("test/DoesNotImplement.java"), + JavaFileObjects.forResource("test/SomeService.java")); + assertThat(compilation).succeededWithoutWarnings(); + assertThat(compilation) + .generatedFile(StandardLocation.CLASS_OUTPUT, "META-INF/services/test.SomeService") + .contentsAsUtf8String() + .isEqualTo("test.DoesNotImplement\n"); + } + + @Test + public void doesNotImplement_suppressed() { + Compilation compilation = + Compiler.javac() + .withProcessors(new AutoServiceProcessor()) + .compile( + JavaFileObjects.forResource("test/DoesNotImplementSuppressed.java"), + JavaFileObjects.forResource("test/SomeService.java")); + assertThat(compilation).succeededWithoutWarnings(); + assertThat(compilation) + .generatedFile(StandardLocation.CLASS_OUTPUT, "META-INF/services/test.SomeService") + .contentsAsUtf8String() + .isEqualTo("test.DoesNotImplementSuppressed\n"); + } + @Test public void generic() { Compilation compilation = Compiler.javac() .withProcessors(new AutoServiceProcessor()) + .withOptions("-Averify=false") .compile( JavaFileObjects.forResource("test/GenericService.java"), JavaFileObjects.forResource("test/GenericServiceProvider.java")); @@ -103,7 +147,22 @@ public void generic() { } @Test - public void genericWithVerifyOption() { + public void genericWithNoVerifyOption() { + Compilation compilation = + Compiler.javac() + .withProcessors(new AutoServiceProcessor()) + .compile( + JavaFileObjects.forResource("test/GenericService.java"), + JavaFileObjects.forResource("test/GenericServiceProvider.java")); + assertThat(compilation).succeeded(); + assertThat(compilation) + .hadWarningContaining( + "Service provider test.GenericService is generic, so it can't be named exactly by" + + " @AutoService. If this is OK, add @SuppressWarnings(\"rawtypes\")."); + } + + @Test + public void genericWithExplicitVerify() { Compilation compilation = Compiler.javac() .withProcessors(new AutoServiceProcessor()) diff --git a/service/processor/src/test/resources/test/DoesNotImplement.java b/service/processor/src/test/resources/test/DoesNotImplement.java new file mode 100644 index 0000000000..1ecfd03b97 --- /dev/null +++ b/service/processor/src/test/resources/test/DoesNotImplement.java @@ -0,0 +1,22 @@ +/* + * Copyright 2023 Google LLC + * + * 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 test; + +import com.google.auto.service.AutoService; + +@AutoService(SomeService.class) +public class DoesNotImplement {} + diff --git a/service/processor/src/test/resources/test/DoesNotImplementSuppressed.java b/service/processor/src/test/resources/test/DoesNotImplementSuppressed.java new file mode 100644 index 0000000000..2aca9c5b79 --- /dev/null +++ b/service/processor/src/test/resources/test/DoesNotImplementSuppressed.java @@ -0,0 +1,23 @@ +/* + * Copyright 2023 Google LLC + * + * 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 test; + +import com.google.auto.service.AutoService; + +@AutoService(SomeService.class) +@SuppressWarnings("AutoService") +public class DoesNotImplementSuppressed {} +