Skip to content

Commit

Permalink
Add explicit check to prevent member injection in Kotlin objects.
Browse files Browse the repository at this point in the history
Fixes #1665
Closes #1739

RELNOTES=Disallow member injection of Kotlin object classes.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=294805598
  • Loading branch information
trevjonez authored and kluever committed Feb 17, 2020
1 parent 583ac4f commit 550d696
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 7 deletions.
23 changes: 19 additions & 4 deletions java/dagger/internal/codegen/validation/InjectValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.google.common.collect.ImmutableSet;
import dagger.internal.codegen.binding.InjectionAnnotations;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
import dagger.internal.codegen.langmodel.Accessibility;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
Expand Down Expand Up @@ -60,21 +61,24 @@ public final class InjectValidator {
private final DependencyRequestValidator dependencyRequestValidator;
private final Optional<Diagnostic.Kind> privateAndStaticInjectionDiagnosticKind;
private final InjectionAnnotations injectionAnnotations;
private final KotlinMetadataUtil metadataUtil;

@Inject
InjectValidator(
DaggerTypes types,
DaggerElements elements,
DependencyRequestValidator dependencyRequestValidator,
CompilerOptions compilerOptions,
InjectionAnnotations injectionAnnotations) {
InjectionAnnotations injectionAnnotations,
KotlinMetadataUtil metadataUtil) {
this(
types,
elements,
compilerOptions,
dependencyRequestValidator,
Optional.empty(),
injectionAnnotations);
injectionAnnotations,
metadataUtil);
}

private InjectValidator(
Expand All @@ -83,13 +87,15 @@ private InjectValidator(
CompilerOptions compilerOptions,
DependencyRequestValidator dependencyRequestValidator,
Optional<Kind> privateAndStaticInjectionDiagnosticKind,
InjectionAnnotations injectionAnnotations) {
InjectionAnnotations injectionAnnotations,
KotlinMetadataUtil metadataUtil) {
this.types = types;
this.elements = elements;
this.compilerOptions = compilerOptions;
this.dependencyRequestValidator = dependencyRequestValidator;
this.privateAndStaticInjectionDiagnosticKind = privateAndStaticInjectionDiagnosticKind;
this.injectionAnnotations = injectionAnnotations;
this.metadataUtil = metadataUtil;
}

/**
Expand All @@ -106,7 +112,8 @@ public InjectValidator whenGeneratingCode() {
compilerOptions,
dependencyRequestValidator,
Optional.of(Diagnostic.Kind.ERROR),
injectionAnnotations);
injectionAnnotations,
metadataUtil);
}

public ValidationReport<TypeElement> validateConstructor(ExecutableElement constructorElement) {
Expand Down Expand Up @@ -271,6 +278,7 @@ public ValidationReport<TypeElement> validateMembersInjectionType(TypeElement ty

if (hasInjectedMembers) {
checkInjectIntoPrivateClass(typeElement, builder);
checkInjectIntoKotlinObject(typeElement, builder);
}
TypeMirror superclass = typeElement.getSuperclass();
if (!superclass.getKind().equals(TypeKind.NONE)) {
Expand Down Expand Up @@ -332,6 +340,13 @@ private void checkInjectIntoPrivateClass(
}
}

private void checkInjectIntoKotlinObject(
TypeElement element, ValidationReport.Builder<TypeElement> builder) {
if (metadataUtil.isObjectClass(element) || metadataUtil.isCompanionObjectClass(element)) {
builder.addError("Dagger does not support injection into Kotlin objects", element);
}
}

private Diagnostic.Kind privateMemberDiagnosticKind() {
return privateAndStaticInjectionDiagnosticKind.orElse(
compilerOptions.privateMemberValidationKind());
Expand Down
9 changes: 6 additions & 3 deletions javatests/dagger/internal/codegen/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ load("//:test_defs.bzl", "GenJavaTests")
package(default_visibility = ["//:src"])

kt_jvm_library(
name = "kotlin_injected_qualifier",
srcs = ["KotlinInjectedQualifier.kt"],
name = "kotlin_sources",
srcs = [
"KotlinInjectedQualifier.kt",
"KotlinObjectWithMemberInjection.kt",
],
deps = [
"//java/dagger:core",
],
Expand All @@ -36,7 +39,7 @@ GenJavaTests(
javacopts = DOCLINT_HTML_AND_SYNTAX,
plugins = ["//java/dagger/internal/codegen/bootstrap"],
deps = [
":kotlin_injected_qualifier",
":kotlin_sources",
"//java/dagger:core",
"//java/dagger/internal/codegen:package_info",
"//java/dagger/internal/codegen:processor",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2020 The Dagger Authors.
*
* 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 dagger.internal.codegen

import javax.inject.Inject

object KotlinObjectWithMemberInjection {
@set:Inject
lateinit var someProperty: String
}

class KotlinClassWithMemberInjectedCompanion {
companion object {
@set:Inject
lateinit var someProperty: String
}
}

class KotlinClassWithMemberInjectedNamedCompanion {
companion object TheCompanion {
@set:Inject
lateinit var someProperty: String
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -271,4 +271,103 @@ public void missingMembersInjectorForKotlinProperty() {
assertThat(compilation)
.hadErrorContaining("Unable to read annotations on an injected Kotlin property.");
}

@Test
public void memberInjectionForKotlinObjectFails() {
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.TestComponent",
"package test;",
"",
"import dagger.Component;",
"import dagger.internal.codegen.KotlinObjectWithMemberInjection;",
"",
"@Component(modules = TestModule.class)",
"interface TestComponent {",
" void inject(KotlinObjectWithMemberInjection injected);",
"}");
JavaFileObject module =
JavaFileObjects.forSourceLines(
"test.TestModule",
"package test;",
"",
"import dagger.Module;",
"import dagger.Provides;",
"",
"@Module",
"class TestModule {",
" @Provides",
" String theString() { return \"\"; }",
"}");
Compilation compilation = daggerCompiler().compile(component, module);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining("Dagger does not support injection into Kotlin objects");
}

@Test
public void memberInjectionForKotlinClassWithCompanionObjectFails() {
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.TestComponent",
"package test;",
"",
"import dagger.Component;",
"import dagger.internal.codegen.KotlinClassWithMemberInjectedCompanion;",
"",
"@Component(modules = TestModule.class)",
"interface TestComponent {",
" void inject(KotlinClassWithMemberInjectedCompanion.Companion injected);",
"}");
JavaFileObject module =
JavaFileObjects.forSourceLines(
"test.TestModule",
"package test;",
"",
"import dagger.Module;",
"import dagger.Provides;",
"",
"@Module",
"class TestModule {",
" @Provides",
" String theString() { return \"\"; }",
"}");
Compilation compilation = daggerCompiler().compile(component, module);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining("Dagger does not support injection into Kotlin objects");
}

@Test
public void memberInjectionForKotlinClassWithNamedCompanionObjectFails() {
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.TestComponent",
"package test;",
"",
"import dagger.Component;",
"import dagger.internal.codegen.KotlinClassWithMemberInjectedNamedCompanion;",
"",
"@Component(modules = TestModule.class)",
"interface TestComponent {",
" void inject(KotlinClassWithMemberInjectedNamedCompanion.TheCompanion injected);",
"}");
JavaFileObject module =
JavaFileObjects.forSourceLines(
"test.TestModule",
"package test;",
"",
"import dagger.Module;",
"import dagger.Provides;",
"",
"@Module",
"class TestModule {",
" @Provides",
" String theString() { return \"\"; }",
"}");
Compilation compilation = daggerCompiler().compile(component, module);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining("Dagger does not support injection into Kotlin objects");
}
}

0 comments on commit 550d696

Please sign in to comment.