Toggle navigation
Toggle navigation
此项目
正在载入...
Sign in
xuning
/
livekitAndroidXuningTest
转到一个项目
Toggle navigation
项目
群组
代码片段
帮助
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
David Liu
2021-12-06 20:14:39 +0900
Browse Files
Options
Browse Files
Download
Plain Diff
Commit
29f196f6525e604b200f4516cef570a6bce91643
29f196f6
2 parents
6c20b7c9
625bc5a9
temp commit
显示空白字符变更
内嵌
并排对比
正在显示
11 个修改的文件
包含
852 行增加
和
1 行删除
.idea/compiler.xml
build.gradle
livekit-lint/.gitignore
livekit-lint/build.gradle
livekit-lint/src/main/java/io/livekit/lint/FlowDelegateUsageDetector.kt
livekit-lint/src/main/java/io/livekit/lint/IssueRegistry.kt
livekit-lint/src/main/java/io/livekit/lint/MediaTrackEqualsDetector.kt
livekit-lint/src/test/java/io/livekit/lint/FlowDelegateUsageDetectorTest.kt
livekit-lint/src/test/java/io/livekit/lint/MediaTrackEqualsDetectorTest.kt
livekit-lint/src/test/resources/MediaStreamTrack.java
settings.gradle
.idea/compiler.xml
查看文件 @
29f196f
<?xml version="1.0" encoding="UTF-8"?>
<project
version=
"4"
>
<component
name=
"CompilerConfiguration"
>
<bytecodeTargetLevel
target=
"11"
/>
<bytecodeTargetLevel
target=
"1.8"
>
<module
name=
"livekit-android.livekit-android-sdk"
target=
"11"
/>
<module
name=
"livekit-android.sample-app"
target=
"11"
/>
</bytecodeTargetLevel>
</component>
</project>
\ No newline at end of file
...
...
build.gradle
查看文件 @
29f196f
...
...
@@ -55,6 +55,9 @@ ext {
androidx_lifecycle:
"2.4.0"
,
dagger
:
"2.27"
,
groupie
:
"2.9.0"
,
junit
:
"4.13.2"
,
junitJupiter
:
"5.5.0"
,
lint
:
"30.0.1"
,
protobuf
:
"3.15.1"
,
]
generated
=
[
...
...
@@ -63,6 +66,17 @@ ext {
deps
=
[
kotlinx_coroutines:
"org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"
,
timber
:
"com.github.ajalt:timberkt:1.5.1"
,
// lint
lint
:
"com.android.tools.lint:lint:${versions.lint}"
,
lintApi
:
"com.android.tools.lint:lint-api:${versions.lint}"
,
lintChecks
:
"com.android.tools.lint:lint-checks:${versions.lint}"
,
lintTests
:
"com.android.tools.lint:lint-tests:${versions.lint}"
,
// tests
junit
:
"junit:junit:${versions.junit}"
,
junitJupiterApi
:
"org.junit.jupiter:junit-jupiter-api:${versions.junitJupiter}"
,
junitJupiterEngine:
"org.junit.jupiter:junit-jupiter-engine:${versions.junitJupiter}"
,
]
annotations
=
[
]
...
...
livekit-lint/.gitignore
0 → 100644
查看文件 @
29f196f
/build
\ No newline at end of file
...
...
livekit-lint/build.gradle
0 → 100644
查看文件 @
29f196f
plugins
{
id
'java-library'
id
'kotlin'
}
java
{
sourceCompatibility
=
JavaVersion
.
VERSION_1_8
targetCompatibility
=
JavaVersion
.
VERSION_1_8
}
dependencies
{
// used for lint rules
compileOnly
deps
.
lintApi
compileOnly
deps
.
lintChecks
compileOnly
deps
.
lintTests
// test lint
testImplementation
deps
.
lint
testImplementation
deps
.
lintTests
// test runners
testImplementation
deps
.
junit
testImplementation
deps
.
junitJupiterApi
testRuntimeOnly
deps
.
junitJupiterEngine
}
test
{
environment
"LINT_TEST_KOTLINC"
,
""
}
\ No newline at end of file
...
...
livekit-lint/src/main/java/io/livekit/lint/FlowDelegateUsageDetector.kt
0 → 100644
查看文件 @
29f196f
@file:Suppress("UnstableApiUsage") // We know that Lint API's aren't final.
/*
* Copyright (C) 2018 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 io.livekit.lint
import com.android.tools.lint.client.api.UElementHandler
import com.android.tools.lint.detector.api.*
import com.intellij.psi.CommonClassNames.JAVA_LANG_OBJECT
import com.intellij.psi.PsiClassType
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import org.jetbrains.uast.*
import org.jetbrains.uast.util.isMethodCall
/** Checks related to DiffUtil computation. */
class FlowDelegateUsageDetector : Detector(), SourceCodeScanner {
override fun getApplicableUastTypes() =
listOf(UBinaryExpression::class.java, UCallExpression::class.java)
override fun createUastHandler(context: JavaContext): UElementHandler? {
return object : UElementHandler() {
override fun visitBinaryExpression(node: UBinaryExpression) {
checkExpression(context, node)
}
override fun visitCallExpression(node: UCallExpression) {
checkCall(context, node)
}
}
}
private fun defaultEquals(context: JavaContext, node: UElement): Boolean {
val resolved: PsiMethod?
when (node) {
is UBinaryExpression -> {
resolved = node.resolveOperator()
if (resolved == null) {
val left = node.leftOperand.getExpressionType() as? PsiClassType
return defaultEquals(context, left)
}
}
is UCallExpression -> {
resolved = node.takeIf { it.isMethodCall() }
?.resolve()
}
is UParenthesizedExpression -> {
return defaultEquals(context, node.expression)
}
else -> {
// We don't know any better
return false
}
}
return resolved?.containingClass?.qualifiedName == MEDIA_STREAM_TRACK
}
private fun defaultEquals(
context: JavaContext,
type: PsiClassType?
): Boolean {
val cls = type?.resolve() ?: return false
if (isKotlin(cls) && (context.evaluator.isSealed(cls) || context.evaluator.isData(cls))) {
// Sealed class doesn't guarantee that it defines equals/hashCode
// but it's likely (we'd need to go look at each inner class)
return false
}
for (m in cls.findMethodsByName("equals", true)) {
if (m is PsiMethod) {
val parameters = m.parameterList.parameters
if (parameters.size == 1 &&
parameters[0].type.canonicalText == MEDIA_STREAM_TRACK
) {
return m.containingClass?.qualifiedName == MEDIA_STREAM_TRACK
}
}
}
return false
}
private fun checkCall(context: JavaContext, node: UCallExpression) {
if (defaultEquals(context, node)) {
// Within cast or instanceof check which implies a more specific type
// which provides an equals implementation?
if (withinCastWithEquals(context, node)) {
return
}
val message = DEFAULT_MSG
val location = context.getCallLocation(
node,
includeReceiver = false,
includeArguments = true
)
context.report(ISSUE, node, location, message)
}
}
/**
* Is this .equals() call within another if check which checks
* instanceof on a more specific type than we're calling equals on?
* If so, does that more specific type define its own equals?
*
* Also handle an implicit check via short circuit evaluation; e.g.
* something like "return a is A && b is B && a.equals(b)".
*/
private fun withinCastWithEquals(context: JavaContext, node: UExpression): Boolean {
var parent = skipParenthesizedExprUp(node.uastParent)
if (parent is UQualifiedReferenceExpression) {
parent = skipParenthesizedExprUp(parent.uastParent)
}
val target: PsiElement? = when (node) {
is UCallExpression -> node.receiver?.tryResolve()
is UBinaryExpression -> node.leftOperand.tryResolve()
else -> null
}
if (parent is UPolyadicExpression && parent.operator == UastBinaryOperator.LOGICAL_AND) {
val operands = parent.operands
for (operand in operands) {
if (operand === node) {
break
}
if (isCastWithEquals(context, operand, target)) {
return true
}
}
}
val ifStatement = node.getParentOfType<UElement>(UIfExpression::class.java, false, UMethod::class.java)
as? UIfExpression ?: return false
val condition = ifStatement.condition
return isCastWithEquals(context, condition, target)
}
private fun isCastWithEquals(context: JavaContext, node: UExpression, target: PsiElement?): Boolean {
when {
node is UBinaryExpressionWithType -> {
if (target != null) {
val resolved = node.operand.tryResolve()
// Unfortunately in some scenarios isEquivalentTo returns false for equal instances
//noinspection LintImplPsiEquals
if (resolved != null && !(target == resolved || target.isEquivalentTo(resolved))) {
return false
}
}
return !defaultEquals(context, node.type as? PsiClassType)
}
node is UPolyadicExpression && node.operator == UastBinaryOperator.LOGICAL_AND -> {
for (operand in node.operands) {
if (isCastWithEquals(context, operand, target)) {
return true
}
}
}
node is UParenthesizedExpression -> {
return isCastWithEquals(context, node.expression, target)
}
}
return false
}
private fun checkExpression(context: JavaContext, node: UBinaryExpression) {
if (node.operator == UastBinaryOperator.IDENTITY_EQUALS ||
node.operator == UastBinaryOperator.EQUALS
) {
val left = node.leftOperand.getExpressionType() ?: return
val right = node.rightOperand.getExpressionType() ?: return
if (left is PsiClassType && right is PsiClassType
&& (left.className == "MediaStreamTrack" || right.className == "MediaStreamTrack")
) {
if (node.operator == UastBinaryOperator.EQUALS) {
if (defaultEquals(context, node)) {
if (withinCastWithEquals(context, node)) {
return
}
val message = DEFAULT_MSG
val location = node.operatorIdentifier?.let {
context.getLocation(it)
} ?: context.getLocation(node)
context.report(ISSUE, node, location, message)
}
} else {
val message = DEFAULT_MSG
val location = node.operatorIdentifier?.let {
context.getLocation(it)
} ?: context.getLocation(node)
context.report(ISSUE, node, location, message)
}
}
}
}
companion object {
private const val MEDIA_STREAM_TRACK = "org.webrtc.MediaStreamTrack"
private const val DEFAULT_MSG =
"Suspicious equality check: MediaStreamTracks should not be checked for equality. Check id() instead."
private val IMPLEMENTATION =
Implementation(FlowDelegateUsageDetector::class.java, Scope.JAVA_FILE_SCOPE)
@JvmField
val ISSUE = Issue.create(
id = "MediaTrackEqualsDetector",
briefDescription = "Suspicious DiffUtil Equality",
explanation = """
`areContentsTheSame` is used by `DiffUtil` to produce diffs. If the \
method is implemented incorrectly, such as using identity equals \
instead of equals, or calling equals on a class that has not implemented \
it, weird visual artifacts can occur.
""",
category = Category.CORRECTNESS,
priority = 4,
androidSpecific = true,
moreInfo = "https://issuetracker.google.com/116789824",
severity = Severity.ERROR,
implementation = IMPLEMENTATION
)
}
}
\ No newline at end of file
...
...
livekit-lint/src/main/java/io/livekit/lint/IssueRegistry.kt
0 → 100644
查看文件 @
29f196f
package io.livekit.lint
import com.android.tools.lint.client.api.IssueRegistry
import com.android.tools.lint.detector.api.CURRENT_API
import com.android.tools.lint.detector.api.Issue
class IssueRegistry : IssueRegistry() {
override val api: Int = CURRENT_API
override val issues: List<Issue>
get() = listOf(MediaTrackEqualsDetector.ISSUE)
}
\ No newline at end of file
...
...
livekit-lint/src/main/java/io/livekit/lint/MediaTrackEqualsDetector.kt
0 → 100644
查看文件 @
29f196f
@file:Suppress("UnstableApiUsage") // We know that Lint API's aren't final.
/*
* Copyright (C) 2018 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 io.livekit.lint
import com.android.tools.lint.client.api.UElementHandler
import com.android.tools.lint.detector.api.*
import com.intellij.psi.CommonClassNames.JAVA_LANG_OBJECT
import com.intellij.psi.PsiClassType
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import org.jetbrains.uast.*
import org.jetbrains.uast.util.isMethodCall
/** Checks related to DiffUtil computation. */
class MediaTrackEqualsDetector : Detector(), SourceCodeScanner {
override fun getApplicableUastTypes() =
listOf(UBinaryExpression::class.java, UCallExpression::class.java)
override fun createUastHandler(context: JavaContext): UElementHandler? {
return object : UElementHandler() {
override fun visitBinaryExpression(node: UBinaryExpression) {
checkExpression(context, node)
}
override fun visitCallExpression(node: UCallExpression) {
checkCall(context, node)
}
}
}
private fun defaultEquals(context: JavaContext, node: UElement): Boolean {
val resolved: PsiMethod?
when (node) {
is UBinaryExpression -> {
resolved = node.resolveOperator()
if (resolved == null) {
val left = node.leftOperand.getExpressionType() as? PsiClassType
return defaultEquals(context, left)
}
}
is UCallExpression -> {
resolved = node.takeIf { it.isMethodCall() }
?.resolve()
}
is UParenthesizedExpression -> {
return defaultEquals(context, node.expression)
}
else -> {
// We don't know any better
return false
}
}
return resolved?.containingClass?.qualifiedName == MEDIA_STREAM_TRACK
}
private fun defaultEquals(
context: JavaContext,
type: PsiClassType?
): Boolean {
val cls = type?.resolve() ?: return false
if (isKotlin(cls) && (context.evaluator.isSealed(cls) || context.evaluator.isData(cls))) {
// Sealed class doesn't guarantee that it defines equals/hashCode
// but it's likely (we'd need to go look at each inner class)
return false
}
for (m in cls.findMethodsByName("equals", true)) {
if (m is PsiMethod) {
val parameters = m.parameterList.parameters
if (parameters.size == 1 &&
parameters[0].type.canonicalText == MEDIA_STREAM_TRACK
) {
return m.containingClass?.qualifiedName == MEDIA_STREAM_TRACK
}
}
}
return false
}
private fun checkCall(context: JavaContext, node: UCallExpression) {
if (defaultEquals(context, node)) {
// Within cast or instanceof check which implies a more specific type
// which provides an equals implementation?
if (withinCastWithEquals(context, node)) {
return
}
val message = DEFAULT_MSG
val location = context.getCallLocation(
node,
includeReceiver = false,
includeArguments = true
)
context.report(ISSUE, node, location, message)
}
}
/**
* Is this .equals() call within another if check which checks
* instanceof on a more specific type than we're calling equals on?
* If so, does that more specific type define its own equals?
*
* Also handle an implicit check via short circuit evaluation; e.g.
* something like "return a is A && b is B && a.equals(b)".
*/
private fun withinCastWithEquals(context: JavaContext, node: UExpression): Boolean {
var parent = skipParenthesizedExprUp(node.uastParent)
if (parent is UQualifiedReferenceExpression) {
parent = skipParenthesizedExprUp(parent.uastParent)
}
val target: PsiElement? = when (node) {
is UCallExpression -> node.receiver?.tryResolve()
is UBinaryExpression -> node.leftOperand.tryResolve()
else -> null
}
if (parent is UPolyadicExpression && parent.operator == UastBinaryOperator.LOGICAL_AND) {
val operands = parent.operands
for (operand in operands) {
if (operand === node) {
break
}
if (isCastWithEquals(context, operand, target)) {
return true
}
}
}
val ifStatement = node.getParentOfType<UElement>(UIfExpression::class.java, false, UMethod::class.java)
as? UIfExpression ?: return false
val condition = ifStatement.condition
return isCastWithEquals(context, condition, target)
}
private fun isCastWithEquals(context: JavaContext, node: UExpression, target: PsiElement?): Boolean {
when {
node is UBinaryExpressionWithType -> {
if (target != null) {
val resolved = node.operand.tryResolve()
// Unfortunately in some scenarios isEquivalentTo returns false for equal instances
//noinspection LintImplPsiEquals
if (resolved != null && !(target == resolved || target.isEquivalentTo(resolved))) {
return false
}
}
return !defaultEquals(context, node.type as? PsiClassType)
}
node is UPolyadicExpression && node.operator == UastBinaryOperator.LOGICAL_AND -> {
for (operand in node.operands) {
if (isCastWithEquals(context, operand, target)) {
return true
}
}
}
node is UParenthesizedExpression -> {
return isCastWithEquals(context, node.expression, target)
}
}
return false
}
private fun checkExpression(context: JavaContext, node: UBinaryExpression) {
if (node.operator == UastBinaryOperator.IDENTITY_EQUALS ||
node.operator == UastBinaryOperator.EQUALS
) {
val left = node.leftOperand.getExpressionType() ?: return
val right = node.rightOperand.getExpressionType() ?: return
if (left is PsiClassType && right is PsiClassType
&& (left.className == "MediaStreamTrack" || right.className == "MediaStreamTrack")
) {
if (node.operator == UastBinaryOperator.EQUALS) {
if (defaultEquals(context, node)) {
if (withinCastWithEquals(context, node)) {
return
}
val message = DEFAULT_MSG
val location = node.operatorIdentifier?.let {
context.getLocation(it)
} ?: context.getLocation(node)
context.report(ISSUE, node, location, message)
}
} else {
val message = DEFAULT_MSG
val location = node.operatorIdentifier?.let {
context.getLocation(it)
} ?: context.getLocation(node)
context.report(ISSUE, node, location, message)
}
}
}
}
companion object {
private const val MEDIA_STREAM_TRACK = "org.webrtc.MediaStreamTrack"
private const val DEFAULT_MSG =
"Suspicious equality check: MediaStreamTracks should not be checked for equality. Check id() instead."
private val IMPLEMENTATION =
Implementation(MediaTrackEqualsDetector::class.java, Scope.JAVA_FILE_SCOPE)
@JvmField
val ISSUE = Issue.create(
id = "MediaTrackEqualsDetector",
briefDescription = "Suspicious DiffUtil Equality",
explanation = """
`areContentsTheSame` is used by `DiffUtil` to produce diffs. If the \
method is implemented incorrectly, such as using identity equals \
instead of equals, or calling equals on a class that has not implemented \
it, weird visual artifacts can occur.
""",
category = Category.CORRECTNESS,
priority = 4,
androidSpecific = true,
moreInfo = "https://issuetracker.google.com/116789824",
severity = Severity.ERROR,
implementation = IMPLEMENTATION
)
}
}
\ No newline at end of file
...
...
livekit-lint/src/test/java/io/livekit/lint/FlowDelegateUsageDetectorTest.kt
0 → 100644
查看文件 @
29f196f
@file:Suppress("UnstableApiUsage", "NewObjectEquality")
package io.livekit.lint
import com.android.tools.lint.checks.infrastructure.LintDetectorTest.bytes
import com.android.tools.lint.checks.infrastructure.TestFile
import com.android.tools.lint.checks.infrastructure.TestFiles.java
import com.android.tools.lint.checks.infrastructure.TestLintTask
import com.android.tools.lint.checks.infrastructure.TestLintTask.lint
import org.junit.Test
class FlowDelegateUsageDetectorTest {
@Test
fun objectEquals() {
lint()
.allowMissingSdk()
.files(
java(
"""
package foo;
class Example {
public boolean foo() {
Object a = new Object();
Object b = new Object();
return a.equals(b);
}
}"""
).indented()
)
.issues(MediaTrackEqualsDetector.ISSUE)
.run()
.expectClean()
}
@Test
fun objectEqualityOperator() {
lint()
.allowMissingSdk()
.files(
java(
"""
package foo;
class Example {
public boolean foo() {
Object a = new Object();
Object b = new Object();
return a == b;
}
}"""
).indented()
)
.issues(MediaTrackEqualsDetector.ISSUE)
.run()
.expectClean()
}
@Test
fun mediaTrackEquals() {
lint()
.allowMissingSdk()
.files(
mediaStreamTrack(),
java(
"""
package foo;
import org.webrtc.MediaStreamTrack;
class Example {
public boolean foo() {
MediaStreamTrack a = new MediaStreamTrack();
MediaStreamTrack b = new MediaStreamTrack();
return a.equals(b);
}
}"""
).indented()
)
.issues(MediaTrackEqualsDetector.ISSUE)
.run()
.expectErrorCount(1)
}
@Test
fun mediaTrackEqualityOperator() {
lint()
.allowMissingSdk()
.files(
mediaStreamTrack(),
java(
"""
package foo;
import org.webrtc.MediaStreamTrack;
class Example {
public boolean foo() {
ABC a = new ABC();
MediaStreamTrack b = new MediaStreamTrack();
a.equals(b);
return a == b;
}
public boolean equals(Object o){
return false;
}
}"""
).indented()
)
.issues(MediaTrackEqualsDetector.ISSUE)
.run()
.expectErrorCount(1)
}
@Test
fun properMediaTrackEquality() {
lint()
.allowMissingSdk()
.files(
mediaStreamTrack(),
java(
"""
package foo;
class Example {
public boolean foo() {
MediaStreamTrack a = new MediaStreamTrack();
MediaStreamTrack b = new MediaStreamTrack();
return a.getId() == b.getId();
}
}"""
).indented()
)
.issues(MediaTrackEqualsDetector.ISSUE)
.run()
.expectClean()
}
}
\ No newline at end of file
...
...
livekit-lint/src/test/java/io/livekit/lint/MediaTrackEqualsDetectorTest.kt
0 → 100644
查看文件 @
29f196f
@file:Suppress("UnstableApiUsage", "NewObjectEquality")
package io.livekit.lint
import com.android.tools.lint.checks.infrastructure.TestFile
import com.android.tools.lint.checks.infrastructure.TestFiles.java
import com.android.tools.lint.checks.infrastructure.TestLintTask
import com.android.tools.lint.checks.infrastructure.TestLintTask.lint
import org.junit.Test
class MediaTrackEqualsDetectorTest {
@Test
fun objectEquals() {
lint()
.allowMissingSdk()
.files(
java(
"""
package foo;
class Example {
public boolean foo() {
Object a = new Object();
Object b = new Object();
return a.equals(b);
}
}"""
).indented()
)
.issues(MediaTrackEqualsDetector.ISSUE)
.run()
.expectClean()
}
@Test
fun objectEqualityOperator() {
lint()
.allowMissingSdk()
.files(
java(
"""
package foo;
class Example {
public boolean foo() {
Object a = new Object();
Object b = new Object();
return a == b;
}
}"""
).indented()
)
.issues(MediaTrackEqualsDetector.ISSUE)
.run()
.expectClean()
}
@Test
fun badMediaTrackEquals() {
lint()
.allowMissingSdk()
.files(
mediaStreamTrack(),
java(
"""
package foo;
import org.webrtc.MediaStreamTrack;
class Example {
public boolean foo() {
MediaStreamTrack a = new MediaStreamTrack();
MediaStreamTrack b = new MediaStreamTrack();
return a.equals(b);
}
}"""
).indented()
)
.issues(MediaTrackEqualsDetector.ISSUE)
.run()
.expectErrorCount(1)
}
@Test
fun mediaTrackEqualityOperator() {
lint()
.allowMissingSdk()
.files(
mediaStreamTrack(),
java(
"""
package foo;
import org.webrtc.MediaStreamTrack;
class Example {
public boolean foo() {
ABC a = new ABC();
MediaStreamTrack b = new MediaStreamTrack();
return a == b;
}
public boolean equals(Object o){
return false;
}
}"""
).indented()
)
.issues(MediaTrackEqualsDetector.ISSUE)
.run()
.expectErrorCount(1)
}
@Test
fun properMediaTrackEquality() {
lint()
.allowMissingSdk()
.files(
mediaStreamTrack(),
java(
"""
package foo;
class Example {
public boolean foo() {
MediaStreamTrack a = new MediaStreamTrack();
MediaStreamTrack b = new MediaStreamTrack();
return a.getId() == b.getId();
}
}"""
).indented()
)
.issues(MediaTrackEqualsDetector.ISSUE)
.run()
.expectClean()
}
}
fun TestLintTask.mediaStreamTrack(): TestLintTask {
return this.files(
java(
"""
package org.webrtc;
class MediaStreamTrack {
int getId(){
return 0;
}
}
"""
).indented()
)
}
fun Any.mediaStreamTrack(): TestFile {
return java(
"""
package org.webrtc;
class MediaStreamTrack {
int getId(){
return 0;
}
}
"""
).indented()
}
\ No newline at end of file
...
...
livekit-lint/src/test/resources/MediaStreamTrack.java
0 → 100644
查看文件 @
29f196f
package
org
.
webrtc
;
class
MediaStreamTrack
{
int
getId
()
{
return
0
;
}
}
\ No newline at end of file
...
...
settings.gradle
查看文件 @
29f196f
...
...
@@ -7,3 +7,4 @@ pluginManagement {
include
':sample-app'
,
':sample-app-compose'
,
':livekit-android-sdk'
rootProject
.
name
=
'livekit-android'
include
':sample-app-common'
include
':livekit-lint'
...
...
请
注册
或
登录
后发表评论