Skip to content

Commit

Permalink
Merge changes from topic "193110413_kotlin_optin_parity" into android…
Browse files Browse the repository at this point in the history
…x-main

* changes:
  Detect method overrides in lambda expressions
  Add support for detecting usages of annotations in overrides
  Eliminate duplicate reports, inspect called member's experimental scope
  • Loading branch information
Treehugger Robot authored and Gerrit Code Review committed Jul 15, 2021
2 parents 5e67171 + 2996dc0 commit e289d65
Show file tree
Hide file tree
Showing 10 changed files with 1,266 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

def isIdeBuild() {
return project.properties['android.injected.invoked.from.ide'] == 'true'
}

plugins {
id("AndroidXPlugin")
id("com.android.library")
Expand All @@ -31,5 +35,10 @@ dependencies {
tasks.withType(KotlinCompile).configureEach {
kotlinOptions {
freeCompilerArgs += [ "-Xuse-experimental=kotlin.Experimental" ]

// Ensure that compilation passes in CLI despite opt-in violations in integration tests.
if (!isIdeBuild()) {
freeCompilerArgs += [ "-Xopt-in=sample.optin.ExperimentalKotlinAnnotation" ]
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="6" by="lint 7.1.0-alpha02" type="baseline" client="cli" name="Lint" variant="all" version="7.1.0-alpha02">
<issues format="6" by="lint 7.1.0-alpha03" type="baseline" client="gradle" name="AGP (7.1.0-alpha03)" variant="all" version="7.1.0-alpha03">

<issue
id="ExperimentalAnnotationRetention"
Expand All @@ -23,6 +23,149 @@
column="18"/>
</issue>

<issue
id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
errorLine1=" static class ConcreteExperimentalInterface implements ExperimentalInterface { // unsafe"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/sample/optin/RegressionTestJava192562469.java"
line="34"
column="59"/>
</issue>

<issue
id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
errorLine1=" public void experimentalMethod() {} // unsafe override"
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/sample/optin/RegressionTestJava192562469.java"
line="36"
column="21"/>
</issue>

<issue
id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
errorLine1=" ExperimentalInterface anonymous = new ExperimentalInterface() { // unsafe"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/sample/optin/RegressionTestJava192562469.java"
line="62"
column="47"/>
</issue>

<issue
id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
errorLine1=" public void experimentalMethod() {} // unsafe override"
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/sample/optin/RegressionTestJava192562469.java"
line="64"
column="25"/>
</issue>

<issue
id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
errorLine1=" ExperimentalInterface lambda = () -> {}; // unsafe"
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/sample/optin/RegressionTestJava192562469.java"
line="67"
column="40"/>
</issue>

<issue
id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
errorLine1=" public void experimentalMethod() {} // unsafe override"
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/sample/optin/RegressionTestJava192562926.java"
line="39"
column="21"/>
</issue>

<issue
id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
errorLine1=" public void experimentalMethod() {} // unsafe override"
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/sample/optin/RegressionTestJava192562926.java"
line="49"
column="25"/>
</issue>

<issue
id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
errorLine1=" StableInterface lambda = () -> {}; // unsafe override"
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/sample/optin/RegressionTestJava192562926.java"
line="52"
column="34"/>
</issue>

<issue
id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
errorLine1=" foo.defaultExperimentalMethod(); // unsafe in Java but safe in Kotlin"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/sample/optin/RegressionTestJava193110413.java"
line="92"
column="13"/>
</issue>

<issue
id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
errorLine1=" foo.experimentalMethod(); // unsafe"
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/sample/optin/RegressionTestJava193110413.java"
line="93"
column="13"/>
</issue>

<issue
id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
errorLine1=" Bar bar = new Bar(); // unsafe"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/java/sample/optin/RegressionTestJava193110413.java"
line="95"
column="19"/>
</issue>

<issue
id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
errorLine1=" bar.stableMethodLevelOptIn(); // unsafe due to experimental class scope"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/sample/optin/RegressionTestJava193110413.java"
line="96"
column="13"/>
</issue>

<issue
id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
errorLine1=" bar.experimentalMethod(); // unsafe"
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/sample/optin/RegressionTestJava193110413.java"
line="97"
column="13"/>
</issue>

<issue
id="UnsafeOptInUsageError"
message="This declaration is opt-in and its usage should be marked with `@sample.optin.ExperimentalJavaAnnotation` or `@OptIn(markerClass = sample.optin.ExperimentalJavaAnnotation.class)`"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright 2021 The Android Open Source Project
*
* 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 sample.optin;

import androidx.annotation.OptIn;

/**
* Regression test for b/192562469 where the lint check does not handle annotation usage in lambdas.
*/
@SuppressWarnings("unused")
public class RegressionTestJava192562469 {
@ExperimentalJavaAnnotation
interface ExperimentalInterface {
void experimentalMethod();
}

/**
* Unsafe usage due to implementation of an experimental interface.
*/
static class ConcreteExperimentalInterface implements ExperimentalInterface { // unsafe
@Override
public void experimentalMethod() {} // unsafe override
}

/**
* Safe usage due to opt-in.
*/
@OptIn(markerClass = ExperimentalJavaAnnotation.class)
static class ConcreteExperimentalInterfaceOptIn implements ExperimentalInterface {
@Override
public void experimentalMethod() {} // safe
}

/**
* Safe usage due to propagation.
*/
@ExperimentalJavaAnnotation
static class ConcreteExperimentalInterfacePropagate implements ExperimentalInterface {
@Override
public void experimentalMethod() {} // safe
}

/**
* Unsafe implementations of an experimental interface.
*/
void regressionTestOverrides() {
@SuppressWarnings("Convert2Lambda")
ExperimentalInterface anonymous = new ExperimentalInterface() { // unsafe
@Override
public void experimentalMethod() {} // unsafe override
};

ExperimentalInterface lambda = () -> {}; // unsafe
}

/**
* Safe implementations of an experimental interface due to opt-in.
*/
@OptIn(markerClass = ExperimentalJavaAnnotation.class)
void regressionTestOverridesOptIn() {
@SuppressWarnings("Convert2Lambda")
ExperimentalInterface anonymous = new ExperimentalInterface() { // safe
@Override
public void experimentalMethod() {} // safe
};

ExperimentalInterface lambda = () -> {}; // safe
}

/**
* Safe implementations of an experimental interface due to propagation.
*/
@ExperimentalJavaAnnotation
void regressionTestOverridesPropagate() {
@SuppressWarnings("Convert2Lambda")
ExperimentalInterface anonymous = new ExperimentalInterface() { // safe
@Override
public void experimentalMethod() {} // safe
};

ExperimentalInterface lambda = () -> {}; // safe
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2021 The Android Open Source Project
*
* 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 sample.optin;

/**
* Regression test for b/192562926 where the lint check should not flag overrides where there is
* no dependency on the superclass, e.g. calls to super().
*/
@SuppressWarnings("unused")
public class RegressionTestJava192562926 {
interface StableInterface {
// This method will show up first in the list provided by PsiClass.allMethods, but it's
// not the method that we want to inspect since it has a concrete implementation.
default void abstractMethodWithDefault() {}

@ExperimentalJavaAnnotation
void experimentalMethod();
}

/**
* Safe override since super is not called.
*/
static class ConcreteStableInterface implements StableInterface {
@Override
public void experimentalMethod() {} // unsafe override
}

/**
* Test different approaches to overriding interface methods.
*/
void regressionTestOverrides() {
@SuppressWarnings("Convert2Lambda")
StableInterface anonymous = new StableInterface() {
@Override
public void experimentalMethod() {} // unsafe override
};

StableInterface lambda = () -> {}; // unsafe override
}
}
Loading

0 comments on commit e289d65

Please sign in to comment.