blob: 6f604119c0777af99f3edbfd2aa95d92a902c51b [file] [log] [blame]
/*
* 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 com.android.tools.lint.detector.api
import com.android.tools.lint.checks.infrastructure.TestFiles.base64gzip
import com.android.tools.lint.checks.infrastructure.TestFiles.java
import com.android.tools.lint.checks.infrastructure.TestFiles.kotlin
import com.intellij.openapi.util.Disposer
import junit.framework.TestCase
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UFile
import org.jetbrains.uast.UResolvable
import org.jetbrains.uast.visitor.UastVisitor
import org.junit.Rule
import org.junit.rules.TemporaryFolder
// Misc tests to verify resolve-handling in the Kotlin UAST initialization.
class ResolveTest : TestCase() {
@get:Rule
val folder = TemporaryFolder()
fun testKotlinReferencesIntoBytecode() {
val tests = arrayOf(
kotlin(
"""
package pkg
import lib.Bar
import lib.Bar2
fun test() {
val bar = Bar("hello1")
val bar2 = Bar2("hello2")
}
"""
).indented(),
libBar
)
val pair = LintUtilsTest.parse(*tests)
val file = pair.first.uastFile
assertEquals(
"""
UFile (package = pkg) [package pkg...]
UImportStatement (isOnDemand = false) [import lib.Bar] => <FAILED>
UImportStatement (isOnDemand = false) [import lib.Bar2] => PsiClass:Bar2
UClass (name = TestKt) [public final class TestKt {...}]
UAnnotationMethod (name = test) [public static final fun test() : void {...}]
UBlockExpression [{...}]
UDeclarationsExpression [var bar: lib.Bar = <init>("hello1")]
ULocalVariable (name = bar) [var bar: lib.Bar = <init>("hello1")]
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) [<init>("hello1")] => PsiMethod:Bar
UIdentifier (Identifier (Bar)) [UIdentifier (Identifier (Bar))]
USimpleNameReferenceExpression (identifier = <init>) [<init>] => <FAILED>
ULiteralExpression (value = "hello1") ["hello1"]
UDeclarationsExpression [var bar2: lib.Bar2 = <init>("hello2")]
ULocalVariable (name = bar2) [var bar2: lib.Bar2 = <init>("hello2")]
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) [<init>("hello2")] => PsiMethod:Bar2
UIdentifier (Identifier (Bar2)) [UIdentifier (Identifier (Bar2))]
USimpleNameReferenceExpression (identifier = <init>) [<init>] => PsiClass:Bar2
ULiteralExpression (value = "hello2") ["hello2"]
""".trimIndent().trim(),
file?.asResolveString()?.trim()
)
Disposer.dispose(pair.second)
}
fun testJavaReferencesIntoBytecode() {
val tests = arrayOf(
java(
"""
package pkg;
import lib.Bar;
import lib.Bar2;
@SuppressWarnings("ALL")
public class Foo2 {
public void test() {
new Bar("hello1");
new Bar2("hello2");
}
}
"""
),
libBar
)
val pair = LintUtilsTest.parse(*tests)
val file = pair.first.uastFile
assertEquals(
"""
UFile (package = pkg) [package pkg...]
UImportStatement (isOnDemand = false) [import lib.Bar] => PsiClass:Bar
UImportStatement (isOnDemand = false) [import lib.Bar2] => PsiClass:Bar2
UClass (name = Foo2) [public class Foo2 {...}]
UAnnotation (fqName = java.lang.SuppressWarnings) [@java.lang.SuppressWarnings(null = "ALL")] => PsiClass:SuppressWarnings
UNamedExpression (name = null) [null = "ALL"]
ULiteralExpression (value = "ALL") ["ALL"]
UMethod (name = test) [public fun test() : void {...}]
UBlockExpression [{...}]
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) [Bar("hello1")] => PsiMethod:Bar
USimpleNameReferenceExpression (identifier = Bar) [Bar] => PsiClass:Bar
ULiteralExpression (value = "hello1") ["hello1"]
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) [Bar2("hello2")] => PsiMethod:Bar2
USimpleNameReferenceExpression (identifier = Bar2) [Bar2] => PsiClass:Bar2
ULiteralExpression (value = "hello2") ["hello2"]
""".trimIndent().trim(),
file?.asResolveString()?.trim()
)
Disposer.dispose(pair.second)
}
/*
Compiled from
$ cat lib/Bar.kt lib/Bar2.java
package lib
data class Bar(val bar: String)
$ cat lib/Bar.kt lib/Bar2.java
package lib;
public class Bar2 {
public Bar2(String msg) {
}
}
*/
private val libBar = base64gzip(
"libs/libBar.jar", "" +
"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" +
"BwAA"
)
}
private fun UFile.asResolveString() = ResolveLogger().apply {
this@asResolveString.accept(this)
}.toString()
class ResolveLogger : UastVisitor {
val builder = StringBuilder()
var level = 0
override fun visitElement(node: UElement): Boolean {
val initialLine = node.asLogString() + " [" + run {
val renderString = node.asRenderString().lines()
if (renderString.size == 1) {
renderString.single()
} else {
renderString.first() + "..." + renderString.last()
}
} + "]"
(1..level).forEach { builder.append(" ") }
builder.append(initialLine)
if (node is UResolvable) {
val resolved = node.resolve()
builder.append(" => ")
if (resolved != null) {
builder.append(resolved)
} else {
builder.append("<FAILED>")
}
}
builder.appendln()
level++
return false
}
override fun afterVisitElement(node: UElement) {
level--
}
override fun toString() = builder.toString().replace("\r", "")
}