
Korean: 
[음악 재생]
오늘 강연 내용은 정적 분석과
커스텀 Lint 규칙의
작성 및 배포입니다
저는 앨런 비버레트입니다
Android 툴킷팀의 소프트웨어 엔지니어입니다
안녕하세요, 저는 라훌입니다
저도 툴킷팀의 소프트웨어 엔지니어입니다
이제 시작하죠
[녹취 불가]
Lint란 무엇일까요?
Lint는 정적 분석기입니다
이 분석기의 목표는
소스 코드를 실행하지 않고
버그를 찾는 데 있습니다
IDE에서 이렇게 오류와
경고가 표시되는 것을
보신 적이 있을 겁니다
이 중 대부분은
Lint에서 찾은 것입니다
오늘 강연은 자체
Lint 규칙을 작성하는 것이기 때문에
스튜디오 설정부터 시작하겠습니다
Lint 규칙을 작성하고 배포하기 위해
어떻게 스튜디오를
설정해야 하는지 알아보겠습니다
그리고 Lint 규칙 테스트
작성에 대해 이야기하겠습니다
UAST와 PSI도 다룰 예정입니다
Kotlin이나 자바 소스 코드를 토대로
Lint 규칙을 작성하고
계신 경우 매우 유용한 내용입니다
이후에는 공통 패턴과
리소스를 다루겠습니다

Japanese: 
[音楽]
静的解析とLintの
カスタムルール作成と
配布についてお話しします
ソフトウェアエンジニアのアランです
同じく
ソフトウェアエンジニアのラフルです
さっそく始めましょう
Lintは静的解析ツールで
ソースコードを実行せずに
バグを発見できます
IDEで表示されるエラーや警告は
Lintが生成しています
Lintルールの作成を説明します
まずLintルールを作成し
配布するために
Studioをセットアップする方法
次にLintルールのテストの作成と
UASTとPSIを説明します
これはKotlinやJavaの
ルール作成に役に立ちます
次にパターンと関連資料を紹介します

Portuguese: 
[MÚSICA]
Hoje vamos falar
sobre análise estática e
escrever e distribuir
regras Lint personalizadas.
Sou Alan Viverette,
engenheiro de software na
equipe Android Toolkit.
Olá, sou Rahul,
também sou engenheiro de software
na equipe do Toolkit.
Vamos começar.
[INAUDÍVEL]
O que é Lint ?
Lint é um analisador estático,
que significa
que a meta é encontrar
bugs no código fonte
sem ter que executá-los.
Vocês já viram erros e avisos
como esses no IDE.
Muitos deles são feitos pelo Lint.
Esta apresentação é sobre
escrever suas próprias regras Lint
então vamos começar com
a configuração do Studio.
Veremos como configurar
o Studio para escrever e
distribuir regras Lint.
Vamos falar sobre escrever
testes para essas regras.
E vamos falar de UAST e PSI.
Isso vai ser útil quando for
escrever regras Lint para
código fonte Kotlin ou Java.
E então falaremos sobre
padrões e recursos comuns.

Indonesian: 
[SUARA MUSIK]
ALAN VIVERETTE: Kali ini, kita
akan membahas analisis statis
serta menulis dan
mendistribusikan aturan Lint kustom.
Saya Alan Viverette.
Saya engineer software
di tim toolkit Android.
RAHUL RAVIKUMAR: Halo, saya Rahul.
Saya juga engineer software
di tim toolkit.
Mari kita mulai.
[...]
Apa itu Lint?
Lint adalah sebuah
penganalisis statis, jadi
tugasnya adalah
menemukan bug di kode sumber
tanpa harus menjalankannya.
Kalian sudah
melihat error & peringatan
yang terlihat seperti ini di IDE.
Sebagian besar
sebenarnya didukung oleh Lint.
Diskusi ini membahas cara
menulis aturan Lint kalian sendiri,
jadi kita akan mulai
dengan menyiapkan Studio.
Dan kita akan mencari tahu
cara menyiapkan
Studio untuk menulis dan
mendistribusikan aturan Lint.
Lalu kita akan bahas tes penulisan
untuk aturan Lint tersebut.
Kita akan membahas UAST dan PSI.
Ini sangat berguna
saat kalian menulis
aturan Lint terhadap
kode sumber Kotlin atau Java.
Lalu kita akan membahas
beberapa pola dan resource yang umum.

English: 
[MUSIC PLAYING]
ALAN VIVERETTE:
Today, we're going
to be talking about
static analysis
and writing and distributing
your own custom Lint rules.
I'm Alan Viverette.
I'm a software engineer on
the Android toolkit team.
RAHUL RAVIKUMAR: Hi, I'm Rahul.
I'm also a software engineer
on the toolkit team.
Let's get started.
[INAUDIBLE]
What is lint?
Lint is a static
analyzer, which means
the objective is to find
bugs in your source code
without having to run them.
You've all seen
errors and warnings
that look like this in the IDE.
A lot of these is
actually powered by Lint.
This talk is about writing
your own Lint rules,
so we will start with
setting up Studio.
And we'll figure
out how to set up
Studio for writing and
distributing Lint rules.
Then we'll talk about writing
tests for those Lint rules.
We'll talk about UAST and PSI.
This would be really
useful when you're
writing Lint rules against
Kotlin or Java source code.
And then we'll talk about some
common patterns and resources.

Chinese: 
今天我们要讲的是静态分析
以及如何编写并分发你自己的定制 Lint 规则
我是 Alan Viverette
是 Android Toolkit 团队的软件工程师
我是 Rahul 也是 Toolkit 团队的软件工程师
我们开始吧
首先 什么是 Lint？
Lint 是一个静态分析器 也就是说
它的目的是 在无需运行源代码的前提下
在你的源代码中寻找 bug
大家都在 IDE 里见过这样的错误和提示
其实其中有很多都是由 Lint 驱动的
今天的演讲的内容是 如何撰写你自己的 Lint 规则
我们先从 Studio 说起
讲讲如何设置 Studio 
并用它来撰写并分发 Lint 规则
然后 我们会讲 如何测试这些 Lint 规则
会讲 UAST 和 PSI
这些东西在你为 Kotlin 或 Java 源代码
编写 Lint 规则时 会很有用
然后 我们再讲一些常见的模式和资源

Spanish: 
Hoy vamos a hablar
sobre el análisis estático
y cómo escribir y distribuir
su propias reglas de Lint.
Soy Alan Viverette,
ingeniero en software
del equipo de herramientas de Android.
Yo soy Rahul
y también soy ingeniero en software
del equipo de herramientas.
Comencemos.
¿Qué es Lint?
Es un analizador de código estático,
es decir, su objetivo
es encontrar errores en tu código fuente
sin que tengas que ejecutarlo.
Todos vieron errores y advertencias
así en el IDE.
Lint genera gran parte de ellos.
En esta charla, explicaremos
cómo escribir reglas de Lint.
Comenzaremos
con la configuración necesaria de Studio
para escribir y distribuir reglas de Lint.
Luego, veremos cómo escribir
pruebas para esas reglas de Lint.
Hablaremos sobre UAST y PSI,
lo que será muy útil
cuando escriban reglas de Lint
en código fuente Kotlin o Java.
Y, por último, veremos
algunos patrones y recursos comunes.

Japanese: 
話すことがたくさんあるので
少し急ぎ足で進めていきます
スライドやソースは共有するので
後で確認できます
最初はJavaライブラリモジュールの
セットアップです
Android AARに
同梱する必要があります
ルールの公開には
ライブラリモジュールが必要です
これがLintモジュールです
これはJavaライブラリで
Lintのバージョンは26.5.1です
Android Gradleのバージョンに
23を足した数字にします
歴史的な事情からそうなっています
コンパイラ限定の依存関係を定義して
lint.jar１つにします
ライブラリモジュールは
lintPublishディレクティブで
ルールをパッケージ化し
Lintモジュールを参照します
アプリがこのライブラリに
依存する場合は

English: 
All right, so this talk, there's
going to be a lot of content.
And I'm going to be going a
little fast, so bear with me.
Don't worry, all the
slides and the source code
will be shared
online, so you can
look at it at your own pace.
So let's do the
initial module setup.
The first thing you need to
do is set up a Java library
module.
That's a place where you
can write your Lint rules,
but you need to package them
as part of an Android AAR,
so you need a library module
to publish those rules.
So let's look at that.
Here's my Lint module.
It's a Java library module.
I'm defining a dependency
on Lint version 26.5.1.
And the rule of
thumb is that you
take the version of your
Android [INAUDIBLE] plugin
and add 23 to it.
Why?
Historical reasons.
Yes.
You define a
compiler-only dependency
because you want
a single lint.jar.
And here's the library module.
So the library module can
package those Lint rules
by using the lintPublish
directive and point to the Lint
module.
And when you do this,
all upstream users
of your library-- so when an
app depends on this library--

Indonesian: 
Baiklah, kali ini akan ada
banyak konten yang dibahas.
Saya akan melakukannya
dengan cepat, bersiaplah.
Tenang, semua slide dan kode sumber
akan dibagikan di
internet, jadi kalian
bisa mempelajarinya sendiri.
Mari lakukan penyiapan modul awal.
Pertama, kalian perlu
menyiapkan modul library Java.
Di sini kalian bisa
menulis aturan Lint, tetapi
kalian perlu memaketkannya
sebagai bagian Android AAR,
jadi kalian perlu modul library
untuk memublikasikan aturan itu.
Mari kita lihat.
Inilah modul Lint saya.
Ini adalah modul library Java.
Saya menentukan dependensi
pada Lint versi 26.5.1.
Kaidahnya, kalian harus
menggunakan versi plugin Android Gradle
dan menambahkan 23.
Mengapa?
Alasan historis.
Ya.
Tentukan dependensi hanya compiler
karena hanya diperlukan satu lint.jar.
Dan inilah modul library.
Modul library dapat
memaketkan aturan Lint tersebut
dengan perintah lintPublish
dan mengarahkan ke modul Lint.
Dan saat melakukannya,
semua pengguna upstream library--
saat aplikasi bergantung
pada library ini--

Korean: 
이번 강연에는 내용이 굉장히 많습니다
조금 빠르게 진행할 테니
잘 따라와주시기 바랍니다
모든 슬라이드와 소스 코드는
온라인으로 공유되기 때문에
나중에 확인하실 수 있습니다
이제 초기 모듈 설정을 해보겠습니다
먼저 자바 라이브러리 모듈을
설정합니다
여기에서 Lint 규칙을 작성하게 됩니다
Lint 규칙은 Android AAR의
일부로 패키징해야 하기 때문에
이 규칙을 게시하기 위한
라이브러리 모듈이 필요합니다
같이 보시겠습니다
여기에 Lint 모듈이 있습니다
이것은 자바 라이브러리 모듈입니다
Lint 버전 26.5.1에
대한 종속성을 정의합니다
경험에 따르면 사용 중인
Android [녹취 불가] 플러그인
버전을 가져와서 23을 추가하는 것이
좋습니다
왜일까요?
역사적인 이유가 있습니다
네
단일 lint.jar가 필요하기 때문에
컴파일러 전용 종속성을 정의합니다
여기에 라이브러리 모듈이 있습니다
라이브러리 모듈은
lintPublish 지시자를 사용하여
Lint 규칙을 패키징하고 Lint 모듈을
가리킵니다
이때 앱이 이 라이브러리에 의존하는 경우
라이브러리의 업스트림 사용자는 모두

Chinese: 
今天的演讲内容非常多
所以我讲得也会比较快 请大家谅解
别担心 所有幻灯片和源代码都会在线分享
大家可以按照自己喜欢的节奏去查看
先来看看初始模块设置
首先 你需要设置一个 Java 代码库模块
你可以在那里编写你的 Lint 规则
但是你需要把它们打包成 Android AAR 的一部分
你需要代码库模块才能发布这些规则
我们来看看
这里是我的 Lint 模块
它是个 Java 代码库模块
我在 Lint 26.5.1 版本定义一个依赖
根据经验 你只需把 Android Gradle 插件的版本号加上23即可
为什么？历史原因
你定义一个仅限编译器的依赖
是因为你想要一个单一的 lint.jar
代码库模块在这里
代码库模块可以使用 lintPublish 指令
打包这些 Lint 规则 并指向 Lint 模块
当你这样做的时候 你的代码库的所有上游用户
当一个应用依赖这个代码库的时候

Spanish: 
En esta charla,
cubriremos mucho contenido,
así que iré bastante rápido.
Espero que puedan seguirme.
No se preocupen. compartiremos en línea
el código fuente y las diapositivas.
Podrán verlos ahí.
Configuremos el módulo inicial.
Para empezar, deben configurar
un módulo de biblioteca Java
Allí, podrán escribir sus reglas de Lint,
pero deberán empaquetarlas
como parte del AAR de Android.
Por ello, necesitan
un módulo de biblioteca para publicarlas.
Veamos eso.
Este es mi módulo de Lint.
Es un módulo de biblioteca Java.
Definí una dependencia
en la versión 26.5.1 de Lint.
Como regla de oro,
deben tomar
su complemento de Gradle para Android
y agregarle 23.
¿Por qué? Por razones históricas.
Sí.
Deben definir una dependencia
exclusiva de compilador
a fin de tener un solo lint.jar.
Este es el módulo de biblioteca,
que puede empaquetar esas reglas de Lint
mediante la directiva lintPublish,
así como dirigir al módulo de Lint.
Si lo hacen así,
todos los usuarios ascendentes
de su biblioteca, si una app
depende de la biblioteca,

Portuguese: 
Vamos ver muito conteúdo.
E em pouco tempo,
então, tenham paciência.
E não se preocupe,
todos os slides
e código fonte
estarão on-line,
para você analisar com tempo.
Vamos configurar módulo inicial
A primeira coisa é configurar um módulo
de biblioteca Java.
É um lugar em que
pode escrever regras Lint,
mas precisa empacotá-las
em um Android AAR
logo precisa de um módulo de
biblioteca para publicá-las.
Vamos ver isso.
Este é meu módulo Lint.
É um módulo de biblioteca Java.
Defini uma dependência
na versão 26.5.1 do Lint.
E a regra geral é que você
pegue a versão do seu
Android Gradle Plug-In
e adicione 23.
Por quê?
Motivos históricos.
Sim.
Você define uma dependência
apenas de compilador
porque quer um lint.jar único.
E aqui está o
módulo de biblioteca.
Então o módulo de biblioteca
pode empacotar essas regras Lint
usando a diretiva lintPublish
e apontando para o
módulo Lint.
E quando faz isso,
todos usuários no upstream
da sua biblioteca,
quando um app depende dela,

Indonesian: 
kita akan otomatis dapat
menggunakan aturan Lint itu.
Berikut modul aplikasi yang
menentukan dependensi penerapan
pada modul Lint.
Kini, aturan yang kalian paketkan
sebagai bagian Android AAR,
akan otomatis diterapkan.
Ini sangat membantu.
Jadi, setiap kali pengguna
mengambil dependensi di library,
aturan Lint kini akan diterapkan.
Sebagai penulis library, kalian dapat
menulis aturan Lint yang dipaketkan
dan diterapkan konsumen kalian.
Selain itu, modul library
atau modul aplikasi
dapat menggunakan
perintah lintChecks dan mengarahkan
ke modul Lint guna
menerapkan pemeriksaan manual.
Jadi, meskipun tidak
diluncurkan sebagai bagian library,
kalian selalu bisa
menggunakan ini.
Untuk meringkas
pembahasan tadi, lintPublish
digunakan untuk
memaketkan file lint.jar dengan AAR.
lintChecks dapat digunakan kapan saja
saat ingin menerapkan pemeriksaan
yang ditentukan di modul library Java.
Langkah pertama dalam
menulis aturan Lint
yakni menentukan IssueRegistry.
IssueRegistry berisi
daftar masalah yang ingin diatasi
dan dicegah.

Spanish: 
verán esas reglas de Lint automáticamente.
Este es un módulo de app
que define una implementación.
Entones, las reglas que empaqueten
como parte del AAR de Android
se aplicarán automáticamente.
Esa propiedad es genial.
Entonces, cada vez que alguien
toma una dependencia de la biblioteca,
se aplican las reglas de Lint.
Como autor de la biblioteca,
pueden escribir reglas de Lint
que se empaqueten
y que puedan implementar sus consumidores.
También un módulo de biblioteca o de app
puede usar la directiva lintCheck
y dirigir al módulo de Lint
para aplicar las verificaciones.
Entonces, incluso aunque
no se envíen como parte de la biblioteca,
pueden usar este método.
Repasemos lo que vimos:
lintPublish permite empaquetar
el archivo lint.jar en el AAR.
Y pueden usar lintChecks
para aplicar las revisiones que definieron
en el módulo de biblioteca Java.
Primero, para escribir una regla de Lint,
deben definir un IssueRegistry.
IssueRegistry tiene
una lista de problemas
que querrán detectar y resolver.

Korean: 
Lint 규칙을 자동으로 사용하게 됩니다
여기에 Lint 모듈에 대한 구현 종속성을
정의하는 앱 모듈이 있습니다
이제 Android AAR의
일부로 패키징되는 규칙이
자동으로 적용됩니다
아주 훌륭한 속성이죠
누군가가 어느 때든
라이브러리에 대한 종속성을 취하는 경우
Lint 규칙이 적용됩니다
여러분은 라이브러리 작성자로서
Lint 규칙을 작성할 수 있으며,
이러한 규칙은 패키징되고
소비자에 의해 적용되는 것입니다
라이브러리 모듈 또는 앱 모듈 역시
lintChecks 지시자를 사용하고
Lint 모듈을 가리켜 자체적으로
확인 사항을 적용할 수 있습니다
따라서 라이브러리의 일부로
제공되지 않는 경우에도
항상 사용할 수 있습니다
지금까지의 내용을
정리하자면 lintPublish는
lint.jar 파일을 AAR로
패키징하는 데 사용됩니다
자바 라이브러리 모듈에서 정의한
확인 사항을 적용하려면
lintChecks를 사용합니다
Lint 규칙 작성의 첫 번째 단계는
IssueRegistry를 정의하는 것입니다
IssueRegistry는 파악하여
발생을 방지하고자 하는
문제의 목록입니다

Portuguese: 
usarão aquelas regras Lint
automaticamente.
Aqui está um módulo de app que
define uma dependência
de implementação no módulo Lint.
Agora as regras que você empacota
no Android AAR, são
aplicadas automaticamente.
É uma propriedade
bem legal.
Sempre que alguém usar uma
dependência na biblioteca,
as regras Lint serão aplicadas.
Como autor de biblioteca,
você pode
escrever regras Lint
que são empacotadas
e aplicadas pelos seus consumidores.
Também um módulo de biblioteca ou app
pode usar a diretiva 
lintChecks e apontar
para o módulo Lint para aplicar
as próprias verificações.
E mesmo que não sejam
enviadas com a biblioteca,
sempre será possível usá-las.
Recapitulando, lintPublish
é o que se usa para 
empacotar o lint.jar no AAR.
E você sempre pode
usar lintChecks
quando quiser aplicar as verificações
definidas no módulo de biblioteca Java.
O primeiro passo para
escrever uma regra Lint
é definir um IssueRegistry.
IssuRegistry tem uma lista
de problemas que quer pegar
e quer evitar que aconteçam.

Japanese: 
自動的にこのルールを使用します
次はLintモジュールの
実装の依存関係を定義する
appモジュールです
これでAARに同梱したルールが
自動で適用されます
ライブラリに依存すると
Lintルールが適用されます
ライブラリ開発者は
ルールをパッケージ化して提供でき
ライブラリ モジュールや
appモジュールはlintChecksで
Lintモジュールを参照し
単体でチェックを適用できるので
ライブラリに同梱されていなくても
いつでも使用できます
要約すると lintPublishで
lint.jarをAARに含め
linkChecksで
Javaライブラリモジュールで
定義したチェックを適用します
ルール作成はまず
IssueRegistryを定義します
これは未然に防ぎたい
Issueのリストで

Chinese: 
都可以自动使用这些 Lint 规则
这里是一个应用模块
它定义了一个对 Lint 模块的实现依赖
现在 那些作为 Android AAR 打包而成的规则
会自动适用 这个非常不错
所以 无论何时 当有人依赖代码库的时候
Lint 规则就会自动适用
作为代码库作者 你可以编写 Lint 规则并打包
然后再由你的用户来应用这些规则
此外 代码库模块或应用模块也可以使用 lintChecks 指令
并指向 Lint 模块来自行执行它们的检查
所以 即使它们不是作为代码库的一部分被推出的
你也随时都可以使用这个
回顾一下我们讲过的东西
lintPublish 是用来通过 AAR 包装 lint.jar 文件的
你可以在任何时候使用 lintChecks
来应用这些你在 Java 库模块中定义的检查规则
撰写 Lint 规则的第一步是定义 IssueRegistry
IssueRegistry 提供了一个需要追踪和避免的问题列表

English: 
we'll get to use those
Lint rules automatically.
So here's an app module which
defines an implementation
dependency on the Lint module.
So now, the rules
that you package
as part of the Android AAR,
they get automatically applied.
That's a really nice property.
So anytime someone takes a
dependency on the library,
the Lint rules now
are being applied.
So as a library author,
you can actually
write Lint rules
that get packaged
and they get applied
by your consumers.
And also a library
module or an app module
can also use the lintChecks
directive and point
to the Lint module to apply
their checks on your own.
So even if they're not being
shipped as part of the library,
you can always use this.
So just to recap what
we saw, the lintPublish
is what is used to package the
lint.jar file with the AAR.
And you can always
use lintChecks
when you want to apply those
checks that you defined
in the Java library module.
The first step in
writing a Lint rule
is defining an IssueRegistry.
The IssueRegistry has a list of
issues that you want to catch
and you want to
prevent from happening.

Portuguese: 
E você tem também os
detectores correspondentes.
Android Lint descobre o
IssueRegistry usando um
padrão de localizador
de serviço.
Vamos ver um exemplo real.
Temos um IssueRegistry.
Estendo o tipo IssueRegistry.
E já defini a lista de problemas
que quero detectar.
Então o localizador do serviço
é basicamente uma entrada
na pasta resources/META-INF
com esse nome grande.
E basta definir uma nova lista
delimitada por linha
de registros de problemas
que são parte do arquivo,
e eles serão detectados pelo
Android Lint automaticamente.
Agora vamos definir
nosso primeiro problema.
Um problema é basicamente
um ID legível,
alguma descrição e
metadados adicionais.
O importante dos metadados
é o detector e o escopo.
O escopo determina o tipo de arquivo
analisado ao executar o lintCheck.
Neste caso, defino o escopo de manifesto,
o que significa que quero analisar
arquivos AndroidManifest.xml.
E este é o problema completo.
Vamos escrever o detector real.

Spanish: 
También tienen
los detectores correspondientes.
Android Lint detecta IssueRegistry
con un patrón localizador de servicios.
Veamos un ejemplo real.
Este es un IssueRegistry.
Extiendo el tipo IssueRegistry
y defino la lista de problemas
que quiero detectar.
Luego, la ubicación de servicios
es una entrada
en su carpeta resources/META-INF,
con ese archivo de nombre muy extenso .
Entonces, deben definir
una nueva lista delimitada
de registro de errores
que son parte del archivo
y Android Lint
los detectará automáticamente.
Ahora, definamos nuestro primer problema.
Un problema es un ID
que pueden leer los seres humanos,
una descripción
y metadatos adicionales.
La parte importante de estos metadatos
es el detector y el alcance.
El alcance determina el tipo de archivos
que buscan cuando ejecutan lintCheck.
En este caso,
definiré el alcance del manifiesto,
lo que significa que quiero analizar
los archivos de AndroidManifest.xml.
Este es el problema completo.
Ahora, escribiremos el detector real.

Korean: 
또한 이에 상응하는 감지기가 있습니다
Android Lint는
서비스 로케이터 패턴을 사용하여
IssueRegistry를 발견합니다
실제 예시를 보겠습니다
여기 IssueRegistry가 있습니다
IssueRegistry 유형을 확장합니다
파악하고자 하는 문제의 목록을
정의합니다
서비스 로케이터는 긴 파일 이름이 붙은
resources/META-INF 폴더의
항목입니다
자료실의 일부이며 새 행으로 구분된
issue registry의 목록을 정의하면
Android Lint에 의해 자동으로 선택됩니다
첫 번째 문제를 정의해보겠습니다
문제는 사람이 읽을 수 있는 ID,
설명, 추가 메타데이터로 구성됩니다
메타데이터의 중요한 부분은
감지기와 scope입니다
scope는 lintCheck를 실행하는 동안
찾는 파일을 정의합니다
이 경우에는 manifest의
scope를 정의하는데요
이는 AndroidManifest.xml
파일을 분석하고자 한다는
의미입니다
이게 전체 문제입니다
이제 실제 감지기를 작성합니다

Indonesian: 
Terdapat juga detektor yang sesuai.
Android Lint menemukan IssueRegistry
menggunakan pola pencari layanan.
Mari lihat contohnya.
Inilah IssueRegistry.
Saya memperluas jenis IssueRegistry-nya.
Dan saya baru menentukan daftar masalah
yang ingin saya atasi.
Pencari layanan adalah entri
di folder resources/META-INF
dengan nama file yang sangat panjang.
Jadi, tentukan saja
daftar baru registry masalah
yang dibatasi garis, yang
merupakan bagian dari arsip,
dan ini akan otomatis
diambil oleh Android Lint.
Sekarang, mari tentukan masalah pertama.
Masalah terdiri dari ID
yang dapat dibaca manusia,
beberapa deskripsi,
dan metadata tambahan.
Bagian penting metadata
adalah detektor dan cakupan.
Cakupan menentukan jenis file
yang kalian cari saat
menjalankan lintCheck.
Dalam kasus ini, saya
menentukan cakupan manifes,
artinya saya ingin menganalisis
file AndroidManifest.xml.
Dan inilah masalah lengkapnya.
Sekarang, mari tulis detektornya.

Chinese: 
还提供了多个相应的侦测器
Android Lint 使用服务定位模式发现 IssueRegistry
我们来看一个真实的例子
这里是一个 IssueRegistry
我继承了 IssueRegistry 类
定义了我想要找出的 Issue 列表
服务定位器本质上讲就是一个
记载在你的 resources/META-INF 文件夹中的条目
而且文件名很长
你把一个新的 IssueRegistry 列表
定义为存档的一部分
它们会自动被 Android 识别
现在 我们来定义第一个问题
问题 本质上就是一个可以被人读懂的 ID
一些描述 以及额外的元数据
元数据的重要部分是侦测器和范围
范围会决定你在运行 lintCheck 的时候看的是哪种文件
在本例中 我准备定义的是 manifest 范围
也就是说 我想分析 AndroidManifest.xml 文件
这里是完整的 issue
下面我们来写一个完整的侦测器

Japanese: 
対応するDetectorがあります
Android Lintはservice locatorで
IssueRegistryを発見します
たとえばIssueRegistryは
IssueRegistry型の拡張で
捕捉したいIssueのリストを定義します
service locatorは
resources/META-INFフォルダにあり
issueRegistryを
行区切りで定義すると
自動的に認識されます
Issueを定義します
IssueにはID、説明、メタデータがあり
メタデータで重要なのは
DetectorとScopeです
ScopeはlintCheckを使って
見るファイルの種類を指定します
AndroidManifest.xmlファイルの
解析のために
マニフェストのスコープを
定義しています
Issueは以上です
次のDetectorは

English: 
And you also have the
corresponding detectors.
Android Lint discovers the
IssueRegistry using a service
locator pattern.
Let's look at a real example.
Here's an IssueRegistry.
I extend the IssueRegistry type.
And I just defined
the list of issues
that I'm interested in catching.
And then the service locator
essentially is an entry
in your resources/META-INF
folder with that very long file
name.
So you just define
a new line delimited
list of issue registries
that are part of the archive,
and they get picked up by
Android Lint automatically.
And now, let's define
our first issue.
An issue is essentially
a human-readable ID,
some description, and
some additional metadata.
The important part
of the metadata
is the detector and the scope.
Scope determines
what kind of files
you're looking at when you're
running your lintCheck.
In this case, I'm defining
the scope of manifest,
which means I'm
interested in analyzing
AndroidManifest.xml files.
And so this is the full issue.
Now, let's write
the actual detector.

Korean: 
문제가 감지기를 가리키고
감지기는 감지기 유형을 확장합니다
그리고 XmlScanner라고 하는
전문화된 기능이 사용됩니다
AndroidManifest.xml의 본질인
XML을 직접 파싱할 필요가 없습니다
Lint에서 훌륭한 콜백 스타일
API를 제공하기 때문입니다
찾고자 하는 것을 Lint에 알리면
준비가 됐을 때 Lint에서 알려줍니다
여기에서는
AndroidManifest.xml에 정의된
모든 manifest 요소를 찾고자 합니다
해당하는 사례가 발견되면
visitElement 콜백을 사용하여 알려줍니다
저는 지금 하는 게 거의 없습니다
문제를 많이 감지하는
감지기를 정의할 뿐입니다
모든 파일의 끝에
afterCheckFile 콜백이 있습니다
ID, 위치, 설명과 함께
문제를 보고합니다
이제 감지기가
AndroidManifest.xml 파일을 찾을 때마다
문제로 인식하고 알려줍니다
실제 환경에서는 하지 마시기 바랍니다
이 작업은 개발자에게는 귀찮지만
워크플로를 테스트하기에는 좋은 방법입니다

Indonesian: 
Masalah ini juga mengarah ke detektor,
jadi detektor akan, sekali
lagi, memperluas jenis detektor.
Dan akan menggunakan
spesialisasi yang disebut XmlScanner.
Daripada harus
menguraikan XML secara manual,
yang merupakan fungsi AndroidManifest.xml,
Lint memberikan API
gaya callback yang hebat.
Jadi, kalian dapat memberi tahu Lint
apa yang ingin ditemukan,
dan Lint akan memanggil kembali saat siap.
Di sini, saya tertarik
untuk menemukan
semua elemen manifes yang
ditentukan di AndroidManifest.xml.
Lalu, saat menemukan semua instance,
Lint akan menggunakan callback
visitElement untuk memanggil kembali.
Jadi, saya tidak perlu melakukan apa pun.
Saya hanya perlu menentukan
detektor yang membuat banyak komplain.
Jadi, di akhir setiap file,
terdapat callback afterCheckFile.
Dan saya melaporkan masalah dengan ID,
lokasi, dan deskripsi.
Setiap kali detektor menemukan
file AndroidManifest.xml,
detektor akan membuat komplain.
Jangan dilakukan saat produksi.
Developer bisa marah,
namun inilah cara
ampuh menguji alur kerja.
Sekarang, mari tulis
tes cepat untuk aturan Lint.

English: 
The issue also pointed
to the detector,
so the detector is, again,
extending the detector type.
And it's using a specialization
called XmlScanner.
Rather than having to
parse XML on my own,
which is what
AndroidManifest.xml is,
Lint gives you a really
nice callback-style API.
So you can tell Lint what
you're interested to find,
and it'll call you
back when it's ready.
So here, I'm saying I'm
interested in finding
all manifest elements defined
in AndroidManifest.xml.
And then when it
finds those instances,
it will use the visitElement
callback to call you back.
So now, notice I'm not
really doing anything.
What I'm doing is defining a
detector that complains a lot.
So at the end of every file, I
get an afterCheckFile callback.
And I'm reporting an
issue with the ID,
and the location, as
well as the description.
Now anytime this
detector encounters
an AndroidManifest.xml
file, it will complain.
Don't do this in production.
You'll really annoy
your developers,
but this is a good way
to test your workflow.

Portuguese: 
O problema também
apontou para o detector,
logo o detector está, de novo,
estendendo o tipo detector.
E usando uma especialização
chamada XmlScanner.
Em vez de ter que analisar o XML sozinho,
que é o AndroidManifest.xml,
Lint oferece a você
uma boa API de estilo callback.
E você diz ao Lint o que quer encontrar,
e ele retorna quando estiver pronto.
Aqui digo que quero encontrar
todos os elementos de manifesto
definidos em AndroidManifest.xml.
E quando ele encontrar instâncias,
ele usa o callback visitElement
para retornar para você.
Veja que não estou fazendo nada.
Estou definindo um
detector que reclama muito.
Então no fim de cada aquivo,
tenho um callback afterCheckFile.
E reporto um problema com ID
e o local e a descrição.
Agora sempre que o detector encontrar
um arquivo AndroidManifest.xml,
ele reclamará.
Não faça isso
na produção.
Vai irritar muito
os desenvolvedores.
Mas é um jeito de
testar fluxo de trabalho.

Chinese: 
Issue 也会指向侦测器
这里继承一下侦测器类
它使用的是一个特殊版 名叫 XmlScanner
与其自己去解析 XML 
也就是指 AndroidManifest.xml 这个文件 不如使用 Lint
Lint 提供了一个非常不错的回调式 API
你可以告诉 Lint 你想找的是什么
它会在准备就绪的时候通知你
这里我说 我想找的是所有
在 AndroidManifest.xml 中定义的清单元素
然后 在它找到这些实例的时候
它会使用 visitElement 回调来通知你
请注意 现在我其实还没做任何事
我只是在定义一个会发出很多报警的侦测器
在每个文件的末尾
我都会得到一个 afterCheckFile 回调
我会使用 ID 位置信息和具体描述来报告问题
每当这个侦测器遇到 AndroidManifest.xml 就会报警
不要在投产版本中这样做
因为这样会让开发者不堪其扰
不过这是个很不错的测试工作流的方式
现在 我们来为这个 Lint 规则写一个快速测试

Spanish: 
El problema también dirige al detector,
por lo que el detector, una vez más,
extiende el tipo de detector.
Y usa una especialización
llamada XmlScanner.
En lugar de analizar XML por mi cuenta,
que es el tipo de archivo
de AndroidManifest.xml,
Lint ofrece una interesante
API de estilo de llamada.
Entonces, pueden indicarle
a Lint qué quieren detectar
y la herramienta
los informará cuando termine.
Aquí, indico que me interesa
encontrar todos los elementos
definidos en AndroidManifest.xml.
Y cuando encuentre esas instancias,
usará el método visitElement
para devolver la llamada.
Como pueden ver, no estoy haciendo nada.
Lo único que hice fue definir
un detector que informa muchos problemas.
Por lo tanto, después de cada archivo,
recibo una llamada de afterCheckFile.
También informaré un error con el ID
y la ubicación, así como la descripción.
Entonces, cada vez que este detector
encuentre un archivo
AndroidManifest.xml, lo informará.
No lo hagan durante la producción;
molesta a los desarrolladores.
Pero sí prueben su flujo de trabajo.

Japanese: 
Issueが参照し
Detector型の拡張で
XmlScannerを使用します
AndroidManifest.xmlを
パースする代わりに
コールバック型のAPIを使用できます
見つけたい対象を指定すると
コールバックします
AndroidManifest.xmlで定義されている
全要素を指定しています
要素が見つかると
visitElementがコールバックします
ここまで口うるさい
Detectorを定義しただけです
afterCheckFileコールバックが
返ってきたら
IssueのID、場所、説明を報告します
AndroidManifest.xmlは
必ずIssueが報告されますが
本番環境では開発の邪魔なので
避けてください

Korean: 
이제 이 Lint 규칙에 대한
간단한 테스트를 작성합니다
Lint에는 훌륭한
테스트 프레임워크가 있습니다
이제 프로그래매틱 방식으로
Lint가 확인하는 파일과
실행 중인 확인 사항
그리고 예상하는 결과를 정의할 수 있습니다
여기에서는 Lint에
단일 manifest 파일을 인라인으로
피드합니다
파일 API를 사용하면 됩니다
이제 문제와 문제의 일부로 정의한
상응하는 감지기를 분석하고 싶다고
지정합니다
실행하면 아무것도 나타나지 않습니다
이 테스트는 실패입니다
감지기에 문제를 많이 정의하기 때문에
이 테스트를 통과시키려면
expect 조건을
이렇게 변경해야 합니다
ID가 있고
설명이 있습니다
Lint 테스트 프레임워크에서 복사한
텍스트 보고서인데
이 테스트에 붙여넣기했습니다
테스트를 작성할 때 좋은 방법이죠
이제 테스트의 대상인
파일이 생겼으므로
예상했던 것을 확인할 수 있습니다
이 모든 것이 하나의 파일에
있기 때문에 테스트를 이렇게 작성하면
정말 편리합니다
소스 파일에 대한
Lint 규칙 작성으로 넘어가겠습니다

Spanish: 
Ahora, escribiremos
una prueba rápida para esta regla de Lint.
Lint también incluye un gran
marco de trabajo para pruebas.
Ahora, pueden definir qué archivos
ve Lint de forma programática,
qué revisiones ejecutarán
y qué esperan ver como resultado.
Aquí, le brindaré a Lint
un solo archivo de manifiesto intercalado
y puedo hacerlo con las API de archivos.
Luego, indico que quiero analizar
el problema y el detector correspondiente
que definí como parte de él.
Al ejecutar, esperamos no ver nada.
Pero esta prueba fallará.
Recuerden que informamos
muchos errores en el detector,
así que para que la prueba sea exitosa
debemos cambiar la condición esperada
a algo así.
Tiene el ID y una descripción.
Este es el informe textual
que copié
del marco de trabajo de prueba de Lint
y pegué en esta prueba.
Esta es una gran forma
de escribir la prueba.
Pueden incluir el conjunto de archivos
que esperan probar y, luego,
pueden ver los resultados que esperaban.
Todo está en un solo archivo,
por lo que es muy conveniente
escribir pruebas de esta manera.
Hablemos sobre cómo escribir
reglas de Lint para archivos fuente.

Indonesian: 
Lint juga meluncurkan dengan
framework pengujian yang bagus.
Jadi, kalian bisa menentukan
secara terprogram file yang dilihat Lint,
pemeriksaan apa yang dijalankan,
dan apa yang ingin dilihat sebagai hasil.
Di sini, saya ingin memberi
Lint satu inline file manifes
dan kalian bisa
melakukannya dengan API file.
Lalu, misalnya,
saya ingin menganalisis
masalah ini dan detektor yang sesuai
yang ditentukan sebagai bagiannya.
Saat menjalankan, kalian
berharap tak ada masalah.
Sayangnya, tes ini akan gagal.
Ingat, kita membuat
banyak komplain di detektor,
jadi, agar tes ini berhasil
kondisi yang diharapkan
harus diubah menjadi seperti ini.
ID-nya ada.
Deskripsinya juga.
Ini sebenarnya laporan tekstual
yang saya salin dari
framework pengujian Lint
dan saya tempelkan di tes ini.
Ini adalah cara mudah untuk menulis tes.
Jadi, kalian bisa memiliki kumpulan file
yang ingin diuji,
lalu akan muncul
apa yang ingin Anda lihat.
Dan ini semua ada di satu file,
yang memudahkan
penulisan tes dengan cara ini.
Mari kita bahas penulisan
aturan Lint untuk file sumber.

Japanese: 
このルールの簡単なテストを
作成しましょう
Lintのテストフレームワークでは
チェック対象の
ファイルチェックの内容
見たい結果を指定できます
ここではmanifestファイルの１行を
インラインで指定していますが
files APIでも可能です
Issueの解析と
定義したDetectorの使用を
指示しています
結果は取得していませんが
テストは失敗します
テストが通るようにするには
expect条件を変更して
IDと説明を指定します
これはLintの
テストフレームワークから
コピーしたものです
以上がテストの作成方法で
テストしたいファイルを
指定して知りたい結果を
確認できます
全部１つのファイルに収まるので
テストの作成がとても楽です
次はソースファイルのLinkルールです

Chinese: 
Lint 会附带一个非常不错的测试框架
现在你可以用编程的方式来定义 Lint 可以看到哪些文件
你在运行的是哪些检查
以及你希望看到的结果
这里我想给 Lint 提供一个单一 manifest 文件
你可以使用文件 API 来做这件事
然后 你可以分析这个问题
以及你为问题指定的侦测器
运行的时候 你的期待是不会看到任何东西
然而 这个测试会失败
请记住 我们在侦测器中报告了很多次
所以 想要让这个测试通过
就需要把期望状态改成这样
这里有 ID 有描述
这个其实是我从 Lint 测试框架那里复制来的文本报告
我把它粘贴进这个测试
这样来写测试很不错
你可以获取想要测试的文件集
然后你就可以看到自己期望看到的东西
全部都整合在一个文件里 
这样来编写测试非常方便
下面来谈谈如何为源文件编写 Lint 规则

English: 
So now, let's write a quick
test for this Lint rule.
Lint also ships with a really
nice testing framework.
So now, you can programmatically
define what files Lint sees,
and what checks you're
running, and what you expect
to see as a result.
Here, I want to feed
Lint a single
manifest file inline,
and you can do that
using the files API.
And then you can say,
I want to analyze
this issue and the
corresponding detector
that you defined as part of it.
And when you run, you
expect to see nothing.
Now however, this
test will fail.
Remember, we complain
a lot in our detector,
so the way to make
this test pass
is by changing the expect
condition to something
that looks like this.
It has the ID.
It has a description.
This is actually
the textual report
that I copied from the
Lint testing framework
and I pasted it into this test.
So now, this is a really
nice way to write the test.
So you can have the
set of files that you
expect to test
against, and then you
can see what you expect to see.
And it's all in one file, and
so it makes it really convenient
to write tests this way.
Let's talk about writing
Lint rules for source files.

Portuguese: 
Agora vamos escrever um
teste rápido para essa regra Lint.
O Lint é enviado com um
framework bem legal de teste.
Agora você pode definir programaticamente
os arquivos que ele vê
e as verificações executadas
e o que espera
como resultado.
Aqui quero alimentar
Lint com um arquivo de manifesto inline,
e dá para fazer isso usando API Files.
E você pode dizer, quero analisar
esse problema e o detector correspondente
que definiu com parte dele.
E ao executar, você não espera ver nada.
Mas este teste vai falhar.
Lembra que reclamamos muito no detector.
A forma de passar neste teste,
é alterar a condição esperada
para que fique assim.
Tem o ID,
uma descrição.
Este é o relatório textual
que copiei do
framework de teste do Lint
e colei neste teste.
Este é um bom jeito de escrever o teste.
E você pode ter o
conjunto de arquivos que
espera testar e, então,
ver o que espera ver.
E está tudo em um arquivo,
logo é muito conveniente
escrever testes assim.
Vamos falar de escrever
regras Lint para arquivos de fonte.

English: 
So to write Lint rules
against source files,
you need to understand
PSI and UAST.
PSI stands for Program Structure
Interface and UAST stands
for Universal
Abstract Syntax Tree.
UAST nodes are
essentially a superset
of what Java and Kotlin support.
And so the cool thing is when
you use UAST to write your Lint
rules, your Lint rules work for
both Kotlin files as well as
Java files.
You don't have to write
two separate rules
for the same thing.
You can also look at other
files like Gradle and XML files
in your detector.
We wouldn't be touching a lot
about mixed detectors today,
but that's also
something you can do.
Now when you write
your tests, you
want to consume UAST
nodes because they
support both Kotlin and Java.
But the eventual checks you
will write will be against PSI.
PSI is just another
way to represent
the same information
UAST gives you,
but it's what IntelliJ
uses internally.
And a good way to understand
what PSI looks like
is to use the
IntelliJ's PSI Viewer.

Indonesian: 
Untuk menulis aturan
Lint terhadap file sumber,
kalian perlu memahami PSI dan UAST.
PSI adalah Program Structure Interface
dan UAST adalah
Universal Abstract Syntax Tree.
Node UAST adalah superhimpunan
dari apa yang didukung Java dan Kotlin.
Hal menariknya yakni saat menggunakan
UAST untuk menulis aturan Lint,
aturan Lint akan berfungsi
untuk file Kotlin dan Java.
Tidak perlu menulis dua aturan berbeda
untuk hal yang sama.
Kalian juga bisa memeriksa file lain
seperti file Gradle & XML di detektor.
Kami tidak akan membahas banyak
tentang detektor campuran,
tetapi kalian juga bisa menggunakannya.
Saat menulis tes, gunakanlah
node UAST karena
mendukung Kotlin dan Java.
Namun pemeriksaan akhir yang
akan ditulis adalah terhadap PSI.
PSI adalah cara lain untuk menunjukkan
informasi yang sama yang diberikan UAST,
namun inilah yang
digunakan IntelliJ secara internal.
Dan cara mudah untuk
memahami seperti apa hasil PSI
adalah menggunakan
Penampil PSI dari IntelliJ.
Akan ada beberapa resource
yang mengarah

Spanish: 
Para escribir estas reglas,
deben entender PSI y UAST.
PSI es Interfaz
de estructura de programación
y UAST
es Árbol de sintaxis abstracta universal.
Los nodos de UAST son, en esencia,
un enorme conjunto
de elementos compatibles
con Java y Kotlin.
Lo interesante es que, si usan UAST
para escribir sus reglas de Lint,
esas reglas funcionarán
tanto en archivos de Kotlin como de Java.
No tienen que escribir
reglas independientes.
En el detector, también pueden
ver otros archivos, como Gradle o XML
No hablaremos mucho
sobre detectores combinados hoy,
pero pueden implementarlos.
Cuando escriban sus pruebas,
les conviene usar nodos de UAST
porque admiten tanto Kotlin como Java.
Sin embargo, las revisiones finales
se escribirán para PSI.
PSI es otra manera de representar
la misma información que brinda UAST,
pero es lo que IntelliJ
usa a nivel interno.
Una buena forma de ver el aspecto de PSI
es usar el visor de PSI de IntelliJ.

Portuguese: 
Para escrever regras Lint para
arquivos de fonte,
você precisa entender PSI e UAST.
PSI é sigla inglesa para Interface de
Estrutura do Programa,
e UAST para Árvore Sintática
Abstrata Universal.
Os nós da UAST são um superconjunto
do que o Java e o Kotlin suportam.
E o legal é que quando você
usa a UAST para escrever
suas regras Lint, elas funcionam
para arquivos Kotlin e Java.
Não precisa escrever duas
regras separadas
para a mesma coisa.
Também pode ver outros
arquivos, como Gradle e XML,
no seu detector.
Não vamos falar de
detectores mistos hoje,
mas também é algo que você pode fazer.
Agora quando escrever seus testes,
é interessante consumir nós UAST porque
são compatíveis
com Kotlin e Java.
Mas as verificações que você
vai escrever serão em PSI.
PSI é só outro jeito
de representar
a mesma informação dada pela UAST,
mas é o que o Intelij usa internamente.
E um jeito bom de entender
a visualização do PSI
é usar o PSI Viewer do IntelliJ.

Chinese: 
如果你想要为源文件编写 Lint 规则
你就要理解 PSI 和 UAST
PSI 的全称是“程序结构接口”
而 UAST 的全称是“通用抽象语法树”
UAST 节点本质上是 Java 和 Kotlin 所支持的超集
好消息是 当你使用 UAST 编写 Lint 规则的时候
你的 Lint 规则会同时适用于 Kotlin 文件和 Java 文件
无需为同一个对象编写两套规则
你还可以查看其他文件 
比如侦测器中的 Gradle 和 XML 文件
我们今天不准备详细讲解混合侦测器
不过 你确实也可以这么做
在编写测试的时候
你想要使用的是 UAST 节点
因为它们同时支持 Kotlin 和 Java
但是你最终编写的 check 会针对的则是 PSI
PSI 只是把 UAST 给你的信息 换了种方式再表达一遍
不过 IntelliJ 内部使用的就是它
想要了解 PSI 的话 
你可以使用 IntelliJ 的 PSI Viewer
我们会准备一些相关资源 

Korean: 
소스 파일에 대한
Lint 규칙을 작성하려면
PSI와 UAST를 이해해야 합니다
PSI는
Program Structure Interface의 약자이고
UAST는
Universal Abstract Syntax Tree의
약자입니다
UAST 노드는 자바와
Kotlin에서 지원하는 것의 상위 집합입니다
따라서 UAST를 사용하여
Lint 규칙을 작성할 때
Lint 규칙이 Kotlin 파일과
자바 파일을 모두 지원한다는
장점이 있죠
동일한 것에 대해
규칙 두 개를 작성할 필요가
없습니다
감지기에서 Gradle 파일과
XML 파일과 같은 다른 파일도
볼 수 있습니다
오늘 혼합 감지기에
대해서는 다루지 않겠지만
이것도 사용하실 수 있습니다
UAST 노드가 Kotlin과
자바를 모두 지원하기 때문에
테스트를 작성할 때
UAST 노드를 사용하고 싶은
경우가 생길 수 있습니다
하지만 최종적으로 작성된
확인 사항은 PSI에 대해 수행해야 합니다
PIS는 UAST가 제공하는 동일한 정보를
표현하는 또 다른 방법일 뿐입니다
하지만 IntelliJ에서는
이것을 내부적으로 사용합니다
PSI가 어떤 것인지
이해하는 좋은 방법은
IntelliJ의 PSI 뷰어를
사용하는 것입니다

Japanese: 
このルールを作成するには
PSIとUASTの理解が必要です
PSIはプログラム構造
インターフェースのことで
UASTは
ユニバーサル抽象構文木です
そのノードは
JavaとKotlinが対応します
UASTで作ったルールは
KotlinとJavaで有効なので
個別に作らずに済みます
GradleやXMLも
処理できます
今回はDetectorの混在には触れませんが
テストの作成には
KotlinとJavaに
対応したUASTノードが
おすすめです
最終チェックはPSIを使用します
PSIはUASTが提供する情報を
別の形で提示します
PSIを内部的に使用している
IntelliJの
PSI Viewerを使うと
PSIをよく理解できます

Portuguese: 
Teremos alguns recursos que apontarão
como usar essa ferramenta
e analisar o PSI.
Vamos escrever rapidamente
uma regra Lint para o WorkManager.
Trabalho no WorkManager.
E uma das coisas que ele suporta
é chamada de inicialização on-demand
Não vou explicar o que é isso,
mas vamos supor que, por exemplo,
esta é a regra Lint que quero usar.
Quero escrever uma regra Lint que diz,
se houver uma classe que implementa
androidx.work.Configuration.Provider,
uma dessas classes
tem que ser uma
android.app.Application.
Não importa quantas classes
implementam
a interface em si,
desde que haja pelo menos
uma android.app.Application.
Essa é outra classe que está
estendendo
a classe application.
Vamos ver a regra Lint.
Novamente, estou definindo
ID do problema, descrição
e os metadados.
Fiz algumas mudanças em relação
ao detector anterior.
Uma delas é a gravidade.
Estou mudando para fatal,
o que significa

Spanish: 
Tenemos algunos recursos
que indicarán cómo usar la herramienta
y permitirán ver el aspecto de PSI.
Vamos a escribir rápidamente
una regla de Lint para WorkManager.
Yo trabajo con WorkManager
y una de las herramientas que admite
es la inicialización a pedido.
No hablaré en detalle
de la inicialización a pedido,
pero asumiremos
que esa es la regla de Lint
que quiero escribir para el argumento.
Quiero que la regla identifique
que si una clase implementa
androidx.work.Configuration.Provider,
una de esas clases
debe ser un android.app.Application.
No importa cuántas clases
implementen la interfaz,si hay
al menos un android.app.Application.
Esa es la otra clase
que extiende la clase de aplicación.
Veamos directamente la regla de Lint.
Nuevamente, definiré
el ID de problema, la descripción
y ahí están los metadatos.
Hice algunos cambios
con respecto al detector anterior.
Uno es la gravedad.
La cambiaré a fatal,
por lo que si informamos
este error desde el detector,

Korean: 
이 도구를 사용하는 방법과
PSI가 어떤 것인지 확인할 수 있는
리소스가 있습니다
그래서
WorkManager에 대한 Lint 규칙을
빠르게 작성해보겠습니다
저는
WorkManager에서 작업 중입니다
WorkManager에서 지원하는 것 중에
on-demand initialization이 있습니다
on-demand initialization을 설명하지는 않겠지만
일단 이것이 제가 작성하고자 하는
Lint 규칙이라고 가정하겠습니다
androidx.work.Configuration.Provider를
구현하는 클래스가 있을 경우
클래스 중 하나는
android.app.Application여야 한다는
Lint 규칙을 쓰려고 하는 경우입니다
실제 인터페이스 자체를
구현하는 클래스의 개수는
중요하지 않습니다
android.app.Application가
최소 1개 있는 한 말이죠
이는 애플리케이션
클래스를 확장하는 또 다른
클래스입니다
이제 Lint 규칙을 보겠습니다
문제 ID, 설명을 정의하고 있고
여기에 메타데이터가 있습니다
이전 감지기와 비교했을 때
변경 사항이 있습니다
이 중 하나가 심각도입니다
이것을 fatal로 바꾸겠습니다

Chinese: 
教你如何使用这个工具来弄懂 PSI
下面我们来为 WorkManager 编写一个 Lint 规则
我在 WorkManager 上面工作
WorkManager 支持按需初始化
这里不会详细解释按需初始化的含义
不过我们就先假定这就是我想要编写的 Lint 规则吧
我想编写的 Lint 规则的内容是
如果有一些类实现了 androidx.work.Configuration.Provider
那么其中一个类必然是 android.app.Application
不管有多少类实现了接口本身
只要有至少一个 android.app.Application 即可
也就是一个继承了 Application 的类
我们来看 Lint 规则本身
这里我定义问题 ID 添加一些描述 这里是元数据
和之前的侦测器相比 我做出了几个改动
改动之一是严重度 (severity)
我把严重度改成了“致命 (FATAL)”
也就是说 如果我们从侦测器报告这个问题的话

Japanese: 
ツールの使い方や
PSIの仕組みに関する資料も紹介します
次はWorkManagerの
Lintルールです
WorkManagerがサポートする機能に
オンデマンド初期化がありますが
ここでは説明しません
ここで作成するLintルールは
androidx.work.Cofiguration.Providerを
実装するクラスがあったら
１つはandroid.app.Applicationに
するとします
少なくとも１つあれば
インターフェースを実装する
クラスの数は問いません
Applicationクラスを拡張する
別のクラスです
ルールを見ていきます
ID、説明、メタデータを
定義しています
先のDetectorを若干変更し
severityをFATALにしています

Indonesian: 
ke cara kalian dalam menggunakan
fitur tersebut dan melihat tampilan PSI.
Mari lakukan penulisan cepat untuk
aturan Lint di WorkManager.
Saya mengerjakan WorkManager.
Dan salah satu yang didukung WorkManager
adalah inisialisasi sesuai permintaan.
Saya tidak akan menjelaskannya,
namun kita anggap saja bahwa inilah
aturan Lint yang ingin saya tulis.
Saya ingin menulis
aturan Lint yang berisi,
jika ada class yang menerapkan
androidx.work.Configuration.Provider,
salah satu class tersebut haruslah
android.app.Application.
Tidak penting berapa class
yang menerapkan
antarmuka yang sebenarnya,
selama ada setidaknya
satu android.app.Application.
Itulah class lainnya yang
memperluas class aplikasi.
Mari lihat aturan Lint-nya.
Di sini, saya menentukan
ID masalah, deskripsi,
dan ini metadatanya.
Ada perubahan jika dibandingkan
dengan detektor sebelumnya.
Salah satunya adalah severity.
Saya mengubahnya ke FATAL,
yang artinya
jika kita melaporkan
masalah ini dari detektor,

English: 
We'll have some
resources that point
to how you can use that tool
and look at what PSI looks like.
And so let's actually
quickly write
a Lint rule for WorkManager.
I work on WorkManager.
And one of the things
that WorkManager supports
is called on-demand
initialization.
I won't go into what on-demand
initialization is, but let's
assume for the sake
of the argument
that this is the Lint
rule I want to write.
I want to write a Lint
rule that says, hey,
if there is a class that
implements androidx.work.Co
nfiguration.Provider,
one of those classes
has to be an
android.app.Application.
It doesn't matter how
many classes implement
the actual interface itself,
as long as there's at least
one android.app.Application.
That's the other class that's
extending the application
class.
So let's look at the
Lint rule itself.
Here again, I am defining the
issue ID, some description,
and here's the metadata.
There are a few changes
that I made when compared
to the previous detector.
One of them is the severity.
I'm changing it to
fatal, which means

Korean: 
이 문제를 감지기에서 보고하면
컴파일 오류가 발생한다는 의미입니다
이제 다시 감지기 클래스를 가리킵니다
scope가 변경되었습니다
더이상 MANIFEST_SCOPE가 아니라
JAVA_FILE_SCOPE입니다
자바 파일과
Kotlin 소스 파일을 보겠다는 의미입니다
이것이 참조할 전체 문제입니다
이제 감지기를 보겠습니다
감지기는 감지기 유형을 확장하지만
이전 예시에서
사용한 XmlScanner 대신
SourceCodeScanner를 사용합니다
Lint는 콜백 중심의 API를 제공합니다
따라서 androidx.work.Co라는
상위 클래스를 확장하는
클래스를 발견하면 알려달라고
입력합니다
그리고 이제 이 인터페이스를 구현하는
클래스의 인스턴스를 찾으면
visitClass 콜백을 호출합니다
저는 지금 선언 위치가
android.app.Application을
확장하는지 확인하고 있습니다
확인을 위해 편리한
context.evaluator.extendsClass
헬퍼를 사용합니다
context.evaluator는
매우 유용한 유틸리티입니다

Indonesian: 
akan menyebabkan error kompilasi.
Sekali lagi, saya arahkan
ke class detektor.
Dan menurut saya
cakupannya telah berubah.
Bukan lagi MANIFEST_SCOPE,
melainkan JAVA_FILE_SCOPE,
yang artinya
saya akan mencari file Java,
dan file sumber Kotlin.
Berikut masalah lengkapnya
sebagai referensi.
Sekarang, mari lihat detektornya.
Detektor lagi-lagi
memperluas jenis detektor,
namun menggunakan SourceCodeScanner,
bukan XmlScanner
di contoh sebelumnya.
Sekali lagi, Lint memberi kalian
API bagus yang dipicu callback.
Jadi, kalian ingin
dipanggil kembali
saat melihat class yang
memperluas superclass ini,
yaitu
androidx.work.Configuration.Provider.
Dan saat menemukan instance class
yang menerapkan antarmuka ini,
callback visitClass akan dipanggil.
Saya memeriksa apakah
situs deklarasi memperluas
android.app.Application.
Dan untuk ini, saya menggunakan
helper context.evaluator.extendsClass.
context.evaluator adalah
utilitas yang sangat berguna.

Japanese: 
DetectorがこのIssueを報告すると
コンパイル エラーになります
Detectorクラスを参照し
MANIFEST_SCOPEから
JAVA_FILE_SCOPEに変更し
Javaファイルと
Kotolinソースファイルを見にいきます
Issue全体はこのようになっています
DetectorはDetector型を拡張し
SourceCodeScannerを使用しています
androidx.work.Configuration.Provider
を拡張するクラスがあれば
コールバックし
このインターフェースを実装する
クラスのインスタンスが見つかったら
visitClassを呼び出します
android.app.Applicationを
拡張しているかどうか
context.evaluator.extendsClassで
確認します
context.evaluatorは

Spanish: 
el resultado será un error de compilación.
Otra vez dirijo a la clase del detector
y vemos que el alcance cambió.
Ya no es MANIFEST_SCOPE,
sino JAVA_FILE_SCOPE,
lo que significa que revisaré
tanto los archivos Java como los Kotlin.
Este es el error completo
para que tengan de referencia.
Ahora, veamos el detector.
Está extendiendo
otra vez el tipo de detector,
pero usa SourceCodeScanner,
en lugar de XmlScanner
como en el ejemplo anterior.
Nuevamente, Lint
cuenta con una API de devolución de llamada.
De esta manera, me informará
cuando vea clases
que extiendan esta superclase,
que es androidx.work.Configuration.Provider.
Entonces, cuando encuentre
instancias de clases
que implementen esta interfaz,
llamará a visitClass.
Revisaré si el sitio de declaración
extiende android.app.Application.
Para eso, usaré la ayuda
de context.evaluator.extendsClass.
context.evaluator es muy útil.

Chinese: 
就会导致编译错误
所以 我指向侦测器类 
改变了范围
现在不再是 MANIFEST_SCOPE 
而是 JAVA_FILE_SCOPE
也就是说 我要查看 Java 文件和 Kotlin 源文件
这里是用来参考的完整 Issue
下面我们来看看侦测器
侦测器继承 Detector 类
但它使用的是 SourceCodeScanner
而不是先前的例子中提到的 XmlScanner
随后 Lint 给了你一个很好的由回调驱动的 API
这里写的是 当我看到有继承这个超类的类的时候 回调我
这个超类就是 androidx.work.Configuration.Provider
现在 当它找到实现这个接口的类的实例时
它就会调用 visitClass 回调
我在查看 声明那里是否继承 android.app.Application
为此 我使用了 context.evaluator.extendsClass Helper
context.evaluator 是个非常有用的工具

Portuguese: 
se reportamos esse problema
do nosso detector,
o resultado será um erro de compilação.
Novamente aponto para a classe detector.
E digo que o escopo agora mudou.
Não é mais MANIFEST_ESCOPE,
é JAVA_FILE_SCOPE,
o que significa que
vou analisar arquivos
de fonte java e kotlin.
Aqui está o problema todo para referência.
E agora vamos ver o detector
Novamente, ele está
estendendo o tipo de detector,
mas usando SourceCodeScanner
em vez de XmlScanner
do exemplo anterior.
E o Lint oferece uma boa
API orientada para callback.
Você está dizendo
me retorne quando
ver classes que estendam
essa superclasse,
que é
androidx.work.Configuration.Provider.
E quando ele encontra
instâncias de classes
que implementam essa interface,
ele chama o callback visitClass.
E estou verificando se o lugar
de declaração estende
android.app.Application.
E para isso, uso um helper prático,
o context.evaluator.extendsClass
O context.evaluator é um
utilitário bem útil.

English: 
if we report this issue
from our detector, that will
result in a compilation error.
And so again, I point
to the detector class.
And I say the scope
is now changed.
It's no longer
MANIFEST_SCOPE, it's
actually JAVA_FILE_SCOPE,
which means
I'm going to look at Java files,
as well as Kotlin source files.
So here's the full
issue for reference.
And now, let's look
at the detector.
The detector is again
extending the detector type,
but it's using SourceCodeScanner
instead of XmlScanner
in the previous example.
And again, Lint gives you a
very nice callback-driven API.
So you're saying
call me back when
I see classes that extend
this superclass, which
is androidx.work.Co
nfiguration.Provider.
And now when it finds
instances of classes
that implement this
interface, it'll
call the visitClass callback.
And I'm checking for whether
the declaration site extends
android.app.Application.
And for that, I'm using a handy
context.evaluator.extendsClass
helper.
Now, context.evaluator
is a very useful utility.

Spanish: 
Verán que se usa en muchos ejemplos.
Es muy importante que se familiaricen
con este tipo de evaluador.
Alan hablará más en detalle
sobre ese tema.
Después de que se analizaron
todos los archivos,
recibiré otra devolución de llamada:
afterCheckEachProject.
Y si no encontré instancias
de android.app.Application
que extiendan esa interfaz,
puedo reportar el error de esta manera.
El resultado será un error de compilación.
Si encuentran el error
mientras escriben el código,
y no cuando publican el APK,
terminará publicándose
en la etapa de producción.
Para probarlo, como queremos
que la prueba de Lint sea independiente,
no queremos que se vincule
con el android.jar
porque ese es el archivo que se publica
con la clase android.app.Application.
Además, no queremos
vincularlo con WorkManager
porque WorkManager es la biblioteca
que define
la interfaz Configuration.Provider.
Entonces, definimos stubs
que representen esas interfaces
y el intercalado de clases.
Aquí, le indico a Lint

Japanese: 
便利なので愛用されています
このevaluatorに
慣れることが大切です
後ほど詳しく解説します
全ファイルの解析が完了すると
afterCheckEachProjectが返ります
インターフェースを拡張する
android.app.Applicationの
インスタンスがなければ
Issueを報告します
するとコンパイルエラーになり
開発中に発見できるので
エラーを残したままリリースせずに済みます
Lintテストはスタンドアロンで行い
android.jarとはリンクしません
android.app.Applicationクラスを
同梱しているからです
WorkManagerも
Configuration.Providerを定義する
ライブラリなので
そうしたインターフェースや
クラスのスタブを定義します
このフォルダに

Chinese: 
很多例子中均有使用
而且你很需要熟悉这个 evaluator 类
Alan 会详细讲解这方面内容
在所有文件都被分析完之后
我会获取另一个有用的回调
名叫 afterCheckEachProject
如果我没找到实现了那个接口的
android.app.Application 的实例
我就可以像这样上报问题
这会导致编译错误
然后你会在编写代码的时候 而不是发布 APK 之后
才发现这个错误 这样就不会把错误留到生产版了
现在讲测试 因为我们想让 Lint 测试独立运行
而不想链接到 android.jar
因为 android.jar 是一个
和 android.app.Application 类一起生成的 JAR
而且 我们也不想链接到 WorkManager
因为 WorkManager 这个代码库定义了
Configuration.Provider 这个接口
我们定义那些代表内联接口和类的 Stub
现在我们写 Lint 假如现在有一个 Kotlin 测试文件

Portuguese: 
E você verá que é
usado em muitos exemplos.
E é importante para você
se familiarizar com esse tipo evaluator.
Alan vai falar mais disso.
E depois de todos os arquivos analisados,
tenho outro callback útil
chamado afterCheckEachProject.
E se eu não encontrar uma instância
de android.app.Application
que estende essa interface,
posso reportar o problema assim.
E isso vai resultar em
um erro de compilação,
e você encontrará o erro enquanto
escreve o código em vez de ao enviar o APK
e acabar enviando na produção...
você envia o erro na produção.
Agora para testar isso,
como queremos que o teste Lint
seja independente,
não vamos vincular ao android.jar
porque este é JAR enviado
com a classe
android.app.Application.
Nem vamos vincular ao
WorkManager,
porque WorkManager
é a biblioteca que
define a interface
Configuration.Provider.
Então definimos stubs que
representam essas interfaces
e classes inline.
E aqui estou dizendo para o Lint

Indonesian: 
Ini akan digunakan di banyak contoh.
Sangat penting bagi kalian
untuk mengenal jenis evaluator.
Alan akan membahasnya lebih lanjut.
Setelah semua file dianalisis,
akan ada callback afterCheckEachProject
yang juga berguna.
Dan jika tidak menemukan instance
android.app.Application
yang memperluas antarmuka,
saya dapat melaporkan masalah seperti ini.
Dan akan mengakibatkan error kompilasi,
dan akan terjadi error
saat kalian menulis kode,
bukan saat meluncurkan APK,
dan akhirnya, ini
diluncurkan dalam produksi--
lalu error ini
diluncurkan dalam produksi.
Untuk mengujinya,
karena kita ingin tes Lint agar
berdiri sendiri, kita tidak
ingin menautkan ke android.jar
karena android.jar
adalah JAR yang diluncurkan
dengan class android.app.Application.
Kita juga tidak ingin
menautkan ke WorkManager
karena WorkManager adalah library
yang menentukan
antarmuka Configuration.Provider.
Kita menentukan stub
yang menunjukkan antarmuka
dan inline class tersebut.
Di sini, saya tulis, Lint,

English: 
And you will see that
used in a lot of examples.
And it is really
important for you
to be familiar with
this evaluator type.
Alan will talk about
that in more detail.
And after all the
files are analyzed,
I get another useful callback
called afterCheckEachProject.
And if I did not
find an instance
of android.app.Application
that extended that interface,
I can report the
issue like this.
And then this will result
in a compilation error,
and then you find the
error while you're
writing the code rather
than you ship the APK,
and then you end up it
ships in production--
you ship the error
in production.
So now to test this because
we want the Lint test to be
standalone, we don't want to
link against the android.jar
because android.jar
is the JAR that ships
with the
android.app.Application class.
And we also don't want to
link against WorkManager
because WorkManager
is the library that
defines the interface
Configuration.Provider.
So we define stubs that
represent those interfaces
and classes inline.
And so here, I'm
saying, hey, Lint,

Korean: 
많은 예시에서 사용되는 것을 알 수 있죠
이 evaluator 유형은
꼭 알고 계셔야 합니다
앨런이 더 자세히 말씀드릴 예정입니다
모든 파일이 분석되면
afterCheckEachProject라
또 다른 유용한 콜백이 생깁니다
이 인터페이스를 확장한
android.app.Application의
인스턴스를 찾지 못하면
이와 같이 문제를 보고할 수 있습니다
그러고 나서 문제가
컴파일 오류를 유발하면
코드를 작성하는 동안
오류를 찾습니다
이렇게 하지 않고 APK를 전달하면
결국 제작 중에
오류가 발생하게 됩니다
android.jar는 
android.app.Application 클래스와 함께
전달되는 JAR이기 때문에
Lint 테스트를 독립적으로 진행하고
android.jar와 연관되지
않도록 하면서 테스트를 수행합니다
WorkManager의 경우 Configuration.Provider라는
인터페이스를 정의하는 라이브러리이기 때문에
WorkManager와도 연관되지 않도록 합니다
따라서 이러한 인터페이스와
클래스를 인라인으로 나타내는
stub을 정의합니다
이 소스 코드가 있는
다음 폴더 아래에

Spanish: 
que finja la existencia
de un archivo de prueba de Kotlin
definido en la siguiente carpeta
con ese código fuente.
Aquí, solo definí
la forma de la interfaz para la prueba,
en lugar de usar la interfaz real.
Así, pueden definir rápidamente el stub.
Luego, pueden indicar
que ese código fuente
se considere parte del conjunto.
Así, cuando ejecuten pruebas,
podrán probar Lint en el stub
que representa la fuente real,
en lugar de tener que volver a vincular
el código fuente antiguo.
Este es el stub completo.
Aquí hay otro.
Este tendrá más sentido.
Definiré un stub en android/app/Application.
Tiene un solo método onCreate,
por lo que no representa realmente
la clase de la aplicación.
Solo quiero una clase
de marcador de posición para la prueba.
Si la clase existe
durante la ejecución del análisis,
todo estará bien.
Por último, escribiré mi prueba.
Le indicaré a Lint
que mientras estén estos archivos
con entradas de la interfaz
de configuración de WorkManager
que definimos en la diapositiva anterior

Indonesian: 
anggaplah ada file tes Kotlin
yang ditentukan
di bagian folder berikut
dengan kode sumber tersebut.
Lihatlah, saya menentukan
bentuk antarmuka untuk keterujian,
bukan antarmuka yang sebenarnya.
Ini hanyalah cara cepat
untuk menentukan stub.
Lalu, perlakukanlah sumber ini
sebagai bagian kumpulan sumber.
Jadi, saat menjalankan tes,
kalian menjalankan Lint
terhadap stub yang
menunjukkan kode sumber
yang sebenarnya,
dan tak perlu menautkan lagi
ke kode sumber yang lama.
Inilah stub lengkapnya.
Ini stub lainnya.
Ini akan lebih sesuai.
Di sini saya menentukan
stub di android/app/application.
Di sini ada satu metode onCreate.
Ini tidak benar-benar menunjukkan
class aplikasi.
Saya hanya menginginkan class
placeholder yang dapat diperiksa.
Dan selama ada class
saat menjalankan analisis
tidak ada masalah.
Akhirnya, saya dapat menulis tes.
Saya tulis, Lint.
Selama ada file yang
memiliki masukan antarmuka
konfigurasi WorkManager
yang baru kita
tentukan di slide sebelumnya,

Chinese: 
使用那种源代码 被定义在以下文件夹里
请注意 这里我出于可测试性的考虑 只定义接口的形状
而不会完全还原真实的接口状态
这只是一种用来帮助大家快速定义 Stub 的方法而已
然后你可以把这个资源当作资源集的一部分来对待
在你运行测试的时候
你可以在代表真正源代码的 Stub 上运行 Lint 
而无需再次链接到之前的源代码
这里是完整的 Stub
这里是另一个 Stub
这个更合理一些
我在这里的 android/app/Application 里定义一个 Stub
它有一个单一的 onCreate 方法
它并不是 Application 类的全部
不过我想要的只是一个能够检查的占位符类
只要这个类在我运行分析的时候维持存在 就没问题
最后 我可以编写测试了
我说 Lint 只要这些文件拥有
我们在之前的幻灯片中定义的 WORK_MANAGER_CONFIGURATION_INTERFACE 输入

Korean: 
Kotlin 테스트 파일이
정의되어 있는 것으로 가정하도록
Lint에 주문합니다
여기에서 저는 실제
인터페이스였던 것에 충실하기보다
테스트 가능성을 위해
인터페이스 모양만
정의합니다
이렇게 하면 stub을
빠르게 정의할 수 있습니다
그런 다음 이 소스를
소스 세트의 일부로
취급하도록 합니다
테스트를 진행하는 경우
기존 소스 코드에 다시 연결하기 보다는
실제 소스 코드를
나타내는 stub에 대해
Lint를 실행할 수 있습니다
여기에 전체 stub이 있습니다
또 다른 stub입니다
이렇게 하면 더 합리적입니다
여기서 저는 Android 앱 애플리케이션에서
stub을 정의하고 있습니다
단일 onCreate 메서드가 있네요
애플리케이션 클래스를 정확히 표현하지
못합니다
하지만 확인의 기준이 되는
자리표시자 클래스가 필요합니다
분석할 때 클래스가 존재하는 한
문제가 없습니다
이제 드디어 테스트를 작성할 수 있네요
Lint입니다
이전 슬라이드에서 정의한
WorkManager 구성 인터페이스와
Android 애플리케이션
클래스의 인풋이 있는
파일이 있는 한

English: 
pretend there's a
Kotlin test file defined
under the following folder
with that source code.
And here, notice
I'm just defining
the shape of the
interface for testability
rather than being true to
what the actual interface was.
This is just a quick way
for you to define the stub.
And then you are saying
treat this source
to be a part of the source set.
So when you're
running your tests,
you can actually run Lint
against the stub that
represents the real source
code rather than having to link
again to the old source code.
And so here's the full stub.
Here's another stub.
This will make more sense.
Here, I'm defining a stub
in Android app application.
And it has a single
onCreate method.
It is not truly
representative of what
the application class is.
But I just want a placeholder
class that I can check against.
And as long as the class exists
when I'm running my analysis,
everything's OK.
And finally, I
can write my test.
So I say, Lint.
As long as there
are these files that
have input of WorkManager
configuration interface
that we just defined in
the previous slide, as well

Portuguese: 
fingir que existe um
arquivo de teste Kotlin definido
na pasta seguinte com esse código fonte.
E veja que aqui apenas defino
a forma da interface para poder testar
em vez de ser definir de fato a interface.
É um jeito rápido de definir o stub.
E de dizer trate essa fonte
como parte
do conjunto fonte.
Então quando executar seus testes,
você pode executar o Lint no stub que
representa o código fonte
real em vez de ter que
vincular ao código fonte real.
Este é o stub completo.
Aqui tem outro stub.
Esse faz mais sentido.
Aqui defino um stub
em android/app/Application.
E tem um método OnCreate único.
Não representa de verdade
a classe application.
Mas só quero uma classe
marcadora que posso verificar.
Desde que a classe exista ao
executar minha análise,
tudo bem.
E finalmente,
posso escrever meu teste.
Digo, Lint,
desde que existam esses
arquivos que
têm entrada da interface de
configuração do WorkManager
que acabamos de definir no
slide anterior

Japanese: 
Kotlinテストファイルが
定義されていることにしています
インターフェースの
外郭をテスト用に定義しているだけで
実物はないことに注意してください
こうすれば手早く定義できます
ソースはソースセットの
一部として扱います
古いソースコードに
再度リンクするのではなく
実際のソースコードのスタブで
テストを実行できます
これがスタブの全体像です
このスタブは
より明快です
onCreateメソッドが
１つあるだけです
実際のクラスとは違いますが
プレースホルダークラスが必要なだけなので
解析時にクラスが存在していれば
問題ありません
WorkManager
Configuration
インターフェースの入力や
Android Applicationクラスがあり

Japanese: 
Configuration Providerを
実装するAppがあれば
Issueがあれば
見つかっても何も警告しません
applicationサブタイプが
インターフェースを正しく
実装しているからです
次のテストは入力ファイルは同じで
クラスがappの
サブタイプでない場合
Issueが見つかったら
エラーを返すようにしています
以上がスタブを使ってテストを実行し
必要なレポートを手に入れる方法です
この方法なら実際の成果物に頼らず
テストを作成でき
テストをリーンな状態に保てます
Lintは
gradlew:app:lintDebugで
実行できます
レポートはテキストに限らず
XMLやHTML形式でも生成でき
IDや説明の作成時に

English: 
as the Android
application class,
and if I have an app
that correctly implements
the configuration provider that
I specify for Lint as input,
and when I run it
against this issue,
I don't expect to see anything,
because the application subtype
correctly implemented
that interface.
However, in the next test,
when I have the same two input
files, and I have
another class that
implements that
interface but it's not
a subtype of
application, and when
I run it against that issue,
I do expect that error.
So now you can see how I used
those stubs and ran tests
against Lint and got the
expected textual report.
And this is a nice way
of composing your test,
so you don't depend
on real artifacts.
And you can keep your
tests pretty lean.
And finally, don't forget,
at any point in time,
you can run Lint from the
command line using gradlew app
lintDebug.
And so far you've been
looking at textual reports.
But it actually generates a nice
XML as well as an HTML report
with the issue ID,
the full explanation,

Chinese: 
以及 ANDROID_APPLICATION_CLASS
如果我的应用可以正确实现
我为 Lint 定义为输入的 CONFIGURATION_PROVIDER
当我针对这个问题来运行它的时候
我的期望是不要看到任何东西
因为应用子类已经正确实现了那个接口
然而 在下一个测试中 当我有了两个相同的输入文件
以及另一个实现了接口 但却不属于 Application 子类的类
当我针对问题来运行它的时候
我期望会看到一个错误提示
现在大家看到了我是如何使用这些 Stub
如何用 Lint 进行测试
并获取了期望中的文本报告的
用这种方式来编写测试 效果相当不错
无需依赖真实工件
测试也可以维持一个简洁的状态
最后 别忘了 在任意时刻
你都可以使用 ./gradlew :app:lintDebug
通过命令行来运行 Lint
到目前为止 你应该一直都在用文本报告
不过 它也会生成不错的 XML 格式
以及 HTML 格式报告
其中带有问题 ID 完整的说明 

Indonesian: 
juga class aplikasi Android,
dan jika ada aplikasi
yang secara tepat menerapkan
penyedia konfigurasi yang
saya tentukan untuk Lint sebagai input,
dan saat dijalankan terhadap masalah ini,
saya yakin tidak akan melihat apa pun,
karena subjenis aplikasi
secara tepat
menerapkan antarmuka tersebut.
Namun, di tes berikutnya, saat
ada dua file input yang sama,
dan ada class lain yang menerapkan
antarmuka tersebut
namun bukan subjenis aplikasi,
dan saat dijalankan terhadap
masalah tersebut, akan terjadi error.
Jadi, dapat dilihat cara
menggunakan stub dan menjalankan tes
terhadap Lint dan mendapatkan
laporan tekstual yang diharapkan.
Ini adalah cara mudah untuk menyusun tes,
agar Anda tidak perlu bergantung
pada artefak.
Tes kalian akan tetap simpel.
Terakhir, jangan lupa,
kalian bisa menjalankan Lint
kapan saja dari command line
dengan ./gradlew :app :lintDebug.
Kalian sudah melihat laporan tekstual.
Sebenarnya laporan XML dan HTML
yang dihasilkan bagus,
dengan ID masalah,
penjelasan lengkap,

Portuguese: 
e a classe AndroidApplication,
e se eu tiver um app que
implementa bem
o provedor de configuração que
especifico para Lint como entrada,
e quando executá-lo
para esse problema,
espero não ver nada porque
o subtipo de application
implementou corretamente
essa interface.
Contudo, no próximo teste,
quanto tenho os mesmos dois
arquivos de entrada e uma
outra classe que
implementa essa interface,
mas não é
um subtipo de application,
e quando
executo-o para esse problema,
espero sim esse erro.
Agora dá para ver como usei
esses stubs e executei testes
no Lint e recebi o relatório
textual esperado.
E esse é jeito bom de
compor seu teste,
para não depender de
artefatos reais.
E você pode deixar
seus testes enxutos.
E finalmente, não esqueça.
A qualquer momento,
você pode executar o Lint na
linha de comando usando
gradlew :app:lintDebug.
E até agora vimos relatórios textuais.
Mas ele gera um bom
XML e um relatório HTML
com o ID do problema,
explicação completa

Korean: 
그리고 Lint에서 인풋으로 명시한
구성 제공자를 제대로
구현하는 앱이 있는 경우
또한 이 문제에 대해
이것을 실행하는 경우
애플리케이션 하위 유형이
이 인터페이스를 올바로 구현했기 때문에
무언가가 표시될 것이라고
예상하지 않습니다
하지만 다음 테스트에서는
동일한 인풋 파일 두 개가 있고
이 인터페이스를 구현하는
또 다른 클래스가 있는데
이것은 애플리케이션의
하위 유형은 아닙니다
그리고 이 문제에 대해 실행하는 경우
오류를 예상하게 됩니다
이상에서 stub 사용 방법과
Lint에 대한 테스트 진행 방법
그리고 예상한 텍스트 형식의
보고서를 확보하는 방법을 확인했습니다
이는 테스트를 구성하는
좋은 방법이기 때문에
실제 아티팩트에 의존하지 않아도 됩니다
테스트를 간결하게 유지할 수도 있고요
마지막으로
gradlew app lintDebug를
사용하여 명령줄에서
Lint를 실행할 수 있다는 것을
기억하세요
지금까지 텍스트 형식의
보고서를 살펴보았습니다
하지만 문제 ID, 전체 설명
문제를 생성할 때 추가한
모든 메타데이터가 있는

Spanish: 
y la clase de aplicación de Android,
y si tengo una app que implementa bien
el proveedor de configuración
que especifico como entrada para Lint,
cuando ejecute el problema,
espero que no muestre nada,
ya que el subtipo de aplicación
implementó correctamente la interfaz.
Sin embargo, en la próxima prueba,
tendré los dos mismos archivos de entrada
y tendré otra clase
que implementa esa interfaz,
pero no es un subtipo de aplicación,
cuando ejecute ese problema,
esperaré ver ese error.
Ahora, pueden ver
cómo use esos stubs y ejecuté pruebas
de Lint, y cómo obtuve
el informe textual esperado.
Es una gran manera de crear su prueba,
ya que no dependen de artefactos reales.
Además, pueden ejecutar pruebas claras.
Por último, no olviden
que pueden ejecutar pruebas de Lint
en cualquier momento en la línea de comandos
en la app de Gradle lintDebug.
Hasta ahora, vimos informes textuales,
pero en realidad
se generan un informe XML y uno HTML
con el ID de problema,
la explicación completa

Portuguese: 
e outros metadados adicionados
ao criar o problema.
E seus desenvolvedores podem
ver qual problema,
como corrigir etc.
Com isso,
vou passar ao Alan.
Obrigado, Rahul.
[APLAUSO]
Muito bem,
vamos voltar um pouco
e fazer algo bem fácil.
Só queremos encontrar
todas as instâncias
de android.util.Log.wtf e
impedir as pessoas de usá-las.
Alguém aqui já usou Log.wtf?
Ótimo.
Parem.
[RISOS]
Se alguém escrever isso,
queremos mostrar um erro.
Vamos implementar um
SourceCodeScanner de novo.
Desta vez vamos analisar
nomes de métodos aplicáveis.
Esta é só uma lista
de nomes de métodos
de que você quer um callback.
Então quando vir algum .wtf ser chamado,
receberá um callback para visitMethodCall.
Porque estamos olhando só
para o nome do método,
e não sabia da classe,
queremos checar primeiro
usando evaluator, classe super útil,
para ver se está
na classe android.util.Log.

Chinese: 
以及你在创建问题时添加的一切元数据
现在 你的开发者可以看到问题出在哪里 如何修改 等等
现在有请 Alan
谢谢 Rahul
好 现在我们后退一步 来做点容易的事
我们想要找到 android.util.Log.wtf 的所有实例
并阻止人们使用它们
这里有人用过 Log.wtf 吗？
好 不要再用了
如果有人写出了这样的代码 我们就想显示错误
我们会实现 SouceCodeScanner
这次 我们来看看可应用的方法名
这只是一个你想要回调的方法名的列表
当我们看到任何带有 .wtf 后缀的东西被调用的时候
我们都会收到回调 visitMethodCall
因为我们只是在看方法名称
而不知道类 所以我们首先需要
使用鉴别器 (eveluator) 进行检查 鉴别器类非常有用
确保它位于 android.util.Log 类中

Korean: 
HTML 보고서뿐 아니라
훌륭한 XML 보고서도 만듭니다
이제 개발자들은 문제가 무엇인지
파악하고 해결할 수 있죠
이제 앨런에게 넘기겠습니다
라훌, 감사합니다
[박수]
이제 아주 쉬운 내용을
다룰까 합니다
android.util.Log.wtf의
모든 인스턴스를 찾아
해당 인스턴스의 사용을 방지하려고 합니다
혹시 Log.wtf
사용해보신 분 계신가요?
좋습니다
손 그만 드세요
[웃음]
누군가 이것을 작성하는 경우
우리는 오류를 표시하려고 합니다
그래서 저희는
source code scanner를
구현하려고 하려고 합니다
이번에는 적용 가능한
메서드 이름을 살펴보겠습니다
콜백하려고 하는 메서드 이름의
목록입니다
호출 중인 .wtf 항목을 확인하면
visitMethodCall에 대한
콜백을 받게 됩니다
메서드 이름을 확인했을 뿐이고
클래스에 대한 정보는 없기 때문에
매우 유용한 클래스인
evaluator를 사용하여 확인하면
이것이 android.util.Log에
있는지 점검할 수 있습니다

Indonesian: 
dan metadata lainnya
yang ditambahkan
saat membuat masalah.
Developer kalian kini
bisa melihat masalahnya,
cara memperbaikinya,
dan sebagainya.
Akhirnya, saya kembalikan pada Alan.
ALAN VIVERETTE: Terima kasih, Rahul.
[TEPUK TANGAN]
Baik, mari hela nafas sejenak
dan lakukan hal yang sangat mudah.
Kita hanya ingin menemukan
semua instance android.util.Log.wtf
dan mencegah agar
pengguna tidak menggunakannya.
Apa ada yang menggunakan Log.wtf di sini?
Bagus.
Berhentilah.
[TERTAWA]
Jadi, jika seseorang menulis ini,
kita ingin menunjukkan error.
Sekali lagi, kita akan
menerapkan pemindai kode sumber.
Kali ini kita lihat nama metode
yang dapat diterapkan.
Ini hanyalah
daftar nama metode
untuk callback
kalian inginkan.
Jadi, saat melihat apa
pun yang dipanggil .wtf,
kita akan menerima
callback ke visitMethodCall.
Karena kita hanya melihat nama metode,
dan class-nya tidak diketahui,
pertama kita harus memeriksa,
dengan evaluator lagi--
class yang sangat berguna--
untuk memastikan ini telah
berada di class android.util.Log.

Spanish: 
y los metadatos que agregaron
cuando crearon el problema.
Ahora, sus desarrolladores
pueden ver el problema,
buscar una solución y mucho más.
Entonces, le daré el espacio a Alan.
Gracias, Rahul.
Bien, primero retrocedamos
para hacer algo muy sencillo.
Solo buscaremos todas las instancias
de android.util.Log.wtf
para impedir que los usuarios las usen.
¿Alguien usó Log.wtf?
Bien, ya no lo hagan.
Si alguien escribe esto,
queremos mostrar un error.
Entonces, implementaremos
un analizador de código fuente.
Pero esta vez, veremos
nombres de métodos aplicables.
Esta es la lista de nombres de métodos
que deben llamar.
De esta manera, cuando vemos
un elemento llamado .wtf,
recibiremos una devolución
de llamada a visitMethodCall.
Como solo observamos el nombre del método
y este no conoce la clase,
primero debemos revisar
una vez más con el evaluador,
la clase más útil,
para asegurarnos de que se encuentre
en la clase android.util.Log.

Japanese: 
追加したメタデータが
含まれます
これで開発者は問題を把握して
修正できます
私からは以上です
[拍手]
ここでちょっと簡単な
チャレンジです
android.util.Log.wtfの
インスタンスを全部使用不可にします
Log.wtfはご存知ですか?
そうですか
[笑い声]
このコードに対して
エラーを表示します
SourceCodeScannerを実装し
ApplicableMethodNamesで
コールバックさせたい
メソッド名を見ます
.wtfが呼ばれると
visitMethodCallで
コールバックを受けます
クラスが分からないので
evaluatorを使い
android.util.Logクラスの
メソッドであることを確認します

English: 
and all the other
metadata that you added
when you created the issue.
So now your developers can
see what the issue was,
how to fix it, and so on.
With that, I'll hand
it over to Alan.
ALAN VIVERETTE: Thanks, Rahul.
[APPLAUSE]
All right, so let's
take a step back
and do something really easy.
We just want to
find all instances
of android.util.Log.wtf and
prevent people from using them.
Has anybody in
here used Log.wtf?
Great.
Stop it.
[LAUGHTER]
So if somebody writes this,
we want to show an error.
So again, we're going to be
implementing a source code
scanner.
This time we're looking at
applicable method names.
This is just a list
of the method names
that you want a callback on.
So when we see anything
.wtf being called,
we will receive a callback
to visitMethodCall.
Because we were just
looking at the method name,
and it didn't know about the
class, we first want to check,
using the evaluator again--
super useful class--
to make sure that it's on
the android.util.Log class.

Japanese: 
その通りなら使用を報告します
一歩進んで
代わりにLog.eを
使用させることもできます
Alt+Enterキーを押したら
メソッド名のWTFを
Eに置換するようにします
複雑な修正は
キャプチャ グループや正規表現を使用します
robotとindependentを
trueにして
修正をコード全体に反映させます
WTFが大量にあっても
一括で修正されます
報告の仕組みは先ほどと同じです
これで使用が禁止されます
Alt+Shift+Enterキーで
置換します
便利ですね
もう少し複雑なのを見てみましょう
Experimentalアノテーションを
ご存知の方は?
何人かいますね

Spanish: 
Si es así, solo informaremos un uso.
Y podemos dar un paso más:
En lugar de usar WTF,
podemos usar Log.e, un registro de errores.
Podemos crear una rápida solución de Lint
que quizás ya conozcan.
Presionamos Alt+Intro
y Lint hará el resto del trabajo.
Reemplazará el nombre de método WTF por E.
También podemos crear
soluciones de Lint más complejas
usando expresiones regulares
y capturando grupos.
Aquí, solo reemplazaremos
fácilmente algunas strings.
Importante: Establecí independent
y robot en "true",
lo que permite aplicar automáticamente
la solución en toda la base de código.
Si tienen varios usos de WTF
y quieren corregirlos todos a la vez,
Lint puede hacerlo automáticamente.
Luego, haremos el informe
con el mismo mecanismo
que vimos antes.
Veremos que este uso está prohibido.
Si quieren reemplazarlo,
presionen Alt+Shift+Enter
y estará listo.
Genial.
Veamos algo un poco más complicado.
¿Alguien aquí usó
la anotación experimental en Kotlin?
Bien, algunos de ustedes.

English: 
If it is, we're just
going to report a usage.
And we can go a step
further, though.
Instead of using
WTF, maybe we want
people to use Log.e,
error level logging.
So we can create
a Lint quick fix--
which you may be familiar with.
You just hit Alt-Enter, and
Lint does everything for you--
that replaces the
method name WTF
with E. You can make really
complicated Lint fixes
using regular expressions
and capturing groups.
We're just going to do simple
string replacement here.
Important to note-- I'm setting
robot and independent to true.
This allows us to
automatically apply
this fix across the
entire code base.
So if you have a
bunch of WTF usages
that you want to
fix in one pass,
Lint can just automatically
do that for you.
And then we'll report it using
the same reporting mechanism
that we saw earlier.
And now we get this nice
usage is prohibited.
If you want to replace it, you
can just hit Alt-Shift-Enter,
and it's done for you.
Pretty cool.
Let's look at something a
little bit more complicated.
Who here has used the
experimental annotation
in Kotlin?
OK, a couple of people.

Chinese: 
如果答案是肯定的 我们只需要上报一个用例
我们还可以再进一步
不用 .wtf 而是使用 Log.e 错误等级记录
我们可以创建一个 Lint 临时解决方案
大家可能对它比较熟悉
只需点击 Alt-Enter 
然后 Lint 就会为你做好所有事情
这个 Lint 临时解决方案会
把 .wtf 这个方法名替换为 e
你可以使用正则表达式和捕获组
做出非常复杂的 Lint 解决方案
我们只要做一点简单的字符串替换就可以了
请注意 我会把 robot 和 independent 的值都设为 true
这样就可以自动把这个解决方案应用到整个代码库里
如果你想把一批 wtf 用法一次性修改好
Lint 可以全自动替你做到
然后我们会使用先前见过的同样的报告机制来报告它
现在我们看到“该方法被禁止调用”的提示
如果你想替换它 只需点击 Alt-Shift-Enter
然后就好了 非常方便
现在我们来看稍微复杂一些的东西
这里有谁用过 Kotlin 中的 Experimental 注解？
好 有几个人用过

Indonesian: 
Jika iya, kita hanya akan
melaporkan penggunaan.
Kita juga dapat melangkah lebih jauh.
Daripada menggunakan
WTF, mungkin kita ingin
pengguna menggunakan Log.e,
logging tingkat error.
Kita dapat membuat
perbaikan Lint yang cepat--
yang mungkin
sudah dikenal.
Cukup klik Alt-Enter,
dan Lint akan mengurus sisanya--
yakni menggantikan nama metode WTF
dengan E.
Kalian bisa membuat
perbaikan Lint yang rumit
dengan ekspresi reguler
dan kelompok tangkapan.
Kita akan melakukan
penggantian string yang sederhana.
Catatan penting--saya setel
robot dan independent ke true.
Ini memungkinkan
penerapan perbaikan otomatis
pada seluruh basis kode.
Jika memiliki banyak penggunaan WTF
yang ingin diperbaiki dalam satu langkah,
Lint dapat otomatis
melakukannya untuk kalian.
Kami akan melaporkannya
dengan mekanisme pelaporan
yang kita lihat di awal.
Lalu akan muncul
Usage of Log.wtf() is prohibited.
Jika ingin menggantinya,
klik saja Alt-Shift-Enter,
dan selesai.
Keren sekali.
Mari lanjutkan ke
hal yang agak lebih rumit.
Siapa di sini yang pernah
menggunakan anotasi eksperimental
di Kotlin?
Oke, ada beberapa orang.

Portuguese: 
E se estiver, vamos reportar
apenas um uso.
E podemos dar um passo adiante.
Em vez de usar WTF, queremos
que as pessoas usem Log.e,
registro de nível de erro,
Podemos criar uma
correção rápida Lint
que você deve conhecer.
Basta pressionar Alt+Enter,
e o Lint faz tudo para você.
Substitui o nome de método
WTF por E.
Você pode criar correções
Lint bem complicadas
usando expressões regulares
e capturando grupos.
Vamos fazer uma simples substituição
de string aqui.
Veja que estou definindo
robot e independent como true.
Isso nos permite
aplicar automaticamente
essa correção em todo o código fonte.
Então se tiver vários usos de WTF
que quiser corrigir de uma vez
o Lint pode fazer isso automaticamente.
E então vamos reportar usando
o mesmo mecanismo
que vimos antes.
E agora temos este ótimo
aviso de uso proibido.
Se quiser substituir,
é só pressionar Alt+Shift+Enter,
e isso será feito para você.
Super legal.
Vamos ver algo um pouco
mais complicado.
Quem aqui já usou a
anotação experimental
no Kotlin?
Ok, alguns.

Korean: 
만약 그렇다면 usage를 보고하게 됩니다
한 단계 더 나아갈 수도 있습니다
WTF를 사용하는 대신
오류 수준 로깅인 Log.e를
사용하도록 하려는 경우가 있을 수 있습니다
이때는 익숙하실
수도 있는 Lint quick fix를
생성합니다
Alt와 Enter를 누르면
Lint에서 모든 걸 해줍니다
메서드 이름 WTF를 E로 바꿔주죠
정규 표현식을 사용하고 그룹을 캡처하여
정말 복잡한 Lint fix를 만들 수 있습니다
이제 간단한 문자열 교체 작업을 해봅니다
robot과 independent를
true로 설정한 것에 유의하세요
이렇게 하면 이 fix를
코드베이스 전체에
자동으로 적용할 수 있습니다
한 번의 전달로
수정하고자 하는 WTF usage가
많은 경우
Lint가 자동으로 대신해줍니다
그러고 나서 이전에 확인했던
동일한 보고 메커니즘을 사용하여
보고합니다
이제 이 usage 사용을 막습니다
usage를 변경하려면
Alt, Shift, Enter를 누르면
됩니다
좋습니다
이제 좀 더 복잡한
내용으로 넘어가겠습니다
Kotlin에서 experimental
어노테이션을 사용해보신 분
있으신가요?
몇 분 계시네요

Korean: 
Kotlin은 unstable로 설정된 특징에
주석을 달 수 있는
experimental 어노테이션과 관련한
의미 구조를 사용합니다
따라서 아직 완성도가 높은 수준은 아니며
언젠가 없어질 수도 있습니다
저희는 이 의미 구조를
Jetpack 라이브러리에서 사용하고자 했지만
Kotlin 컴파일러가
자바 소스 코드에서 이를 시행하지
못했습니다
그래서 Kotlin 컴파일러에서 사용하는
동일한 의미 구조와
어노테이션을 Java에서 실행할 수 있는
Lint 규칙을 작성했습니다
실제로 해보면 이렇습니다
experimental 어노테이션으로
커스텀 어노테이션에 주석을 달고
feature set 어노테이션을 통해
API 서피스에 주석을 답니다
여기에 TimeTravelProvider가 있습니다
언젠가 사라질 수도 있습니다
이미 없어졌을 수도 있겠네요
이제 코드의 usage가
동일한 어노테이션,
동일한 특징 세트의
일부가 됩니다
그래서 개발자가 작성한 것과
동일한 어노테이션을 갖게 됩니다
아니면 Kotlin UseExperimental
어노테이션을 사용하여
불안정해지는 길을 택할 수도 있습니다
이 두 가지 방법을
사용하면 Kotlin 컴파일러나

Spanish: 
Kotlin fuerza elementos semáticos
en la anotación experimental
que les permiten indicar
que un conjunto de funciones es inestable.
Por ejemplo, indicar que es calidad Alfa
o que luego la quitarán.
Realmente queríamos implementar
estos en las bibliotecas Jetpack.
Pero el compilador de Kotlin
no lo implementa
desde el código Java fuente.
Entonces, escribimos una regla de Lint
que admite implementaciones de Java
con la misma semática
y anotación que usa el compilador Kotlin.
En la práctica, sería implementar 
su propia anotación de manera experimental
y anotar la superficie de su API con
la anotación del conjunto de funciones.
Aquí tenemos un TimeTravelProvider.
Tal vez desaparezca más adelante.
O bien tal vez ya lo hizo.
Luego, el uso en el código
será parte
de la misma anotación, es decir,
el mismo conjunto de funciones,
y tiene la anotación
que escribió el desarrollador.
O bien habilitará esa inestabilidad
con la anotación
UseExperimental de Kotlin.

English: 
Kotlin enforces some
semantics around
the experimental annotation
that allow you to annotate
a feature set as unstable.
So maybe that means
it's alpha quality.
Maybe it's going to
go away eventually.
We really wanted to use this
in the Jetpack libraries.
But the Kotlin compiler
can't enforce this
from Java source code.
So we wrote a Lint
rule that allows
Java enforcement of the
exact same semantics
and exact same annotation
used by the Kotlin compiler.
So in practice, this looks
like annotating your own custom
annotation with
experimental and then
annotating your API surface with
that feature set annotation.
So here we have a
TimeTravelProvider.
And maybe it's going to go away.
Maybe it went away in the past.
And then the usage in
code is going to either
be part of the exact
same annotation--
the exact same feature set.
So it has the same annotation
that the developer wrote.
Or it's going to opt into that
instability with the Kotlin
UseExperimental annotation.
So these are two valid
ways that would not

Indonesian: 
Kotlin menerapkan beberapa semantik
seputar anotasi eksperimental
yang memungkinkan anotasi
kumpulan fitur yang
disetel sebagai tidak stabil.
Mungkin artinya,
kualitasnya alfa.
Mungkin akan menghilang pada akhirnya.
Kami sangat ingin
menggunakannya di library Jetpack.
Namun, compiler Kotlin
tidak bisa menerapkannya
dari kode sumber Java.
Jadi, kami menulis
aturan Lint yang memungkinkan
penerapan Java untuk
semantik yang sama persis
dan anotasi yang sama persis
yang digunakan oleh compiler Kotlin.
Jadi, dalam praktiknya, ini seperti
memberi anotasi pada anotasi kustom
dengan eksperimental, lalu
menganotasi permukaan API
dengan anotasi kumpulan fitur itu.
Di sini terdapat TimeTravelProvider.
Dan mungkin ini akan menghilang.
Mungkin dulunya ini menghilang.
Lalu penggunaan dalam kode akan
menjadi bagian dari anotasi yang sama--
kumpulan fitur yang sama.
Jadi anotasinya sama
seperti yang ditulis developer.
Atau juga akan mengalami
ketidakstabilan dengan
anotasi UseExperimental Kotlin.
Ini adalah dua cara valid yang tidak akan

Japanese: 
Experimentalアノテーションは
あるフィーチャーセットが
アルファ版であり
最終的に廃止予定であると
マークできます
Jetpackライブラリで使いたいけれど
Javaソースコードには強制できません
そこでLintルールを作成し
Javaでも同じセマンティクスと
アノテーションを
強制できるようにしました
カスタムアノテーションを
Experimentalにし
APIにはフィーチャーセットの
アノテーションを付加します
TimeTravelProviderは
廃止予定か廃止済みです
コードでは
同じアノテーションセットの一部
つまり開発者が記述したのと
同じアノテーションか
UseExperimentalの
どちらかを使用します
どちらも有効で

Chinese: 
Kotlin 要求使用 Experimental 注解
把一个不稳定的功能集注解出来
也许这意味着 它的品质是 alpha 版本级别的
也许它最终会消失
我们非常想在 Jetpack 代码库中使用这个功能
但 Kotlin 编译器无法在 Java 源代码上执行这个规则
所以 我们写了一个 Lint 规则
这个规则允许 Java 执行与 Kotlin 编译器
完全相同的语法和完全相同的注解
在实践中 这种做法看起来像是使用 Experimental
个性化地注解你自己的代码
然后再使用 FeatureSet 来注解你的 API
这里有一个 TimeTravelProvider 
也许它会消失 也许它曾经消失过
用法代码要么就是完全相同的注解
和完全相同的功能集的一部分
也就是说 它的注解会和开发者编写的相同
要么就会采用 Kotlin 的 UseExperimental 注解
这两个有效方式都不会在 Kotlin 编译器

Portuguese: 
Kotlin aplica um pouco
da semântica
na anotação experimental
que permite anotar
um conjunto de recursos como instável.
Talvez signifique qualidade alpha.
Talvez seja algo temporário.
Queríamos muito usar isso
nas bibliotecas do Jetpack.
Mas o Kotlin Compiler não pode aplicar
isso no código fonte Java.
Então escrevemos uma regra Lint
que permite
a aplicação em Java da mesma
semântica exatamente
e da mesma anotação
usada no Kotlin Compiler.
Na prática, parece que
você está anotando
sua anotação personalizada com
experimental e
anotando a superfície da API com
essa anotação de conjunto de recurso.
Aqui temos um TimeTravelProvider.
E talvez seja temporário.
Talvez já tenha passado.
E então o uso no código vai ser
parte da mesma anotação exatamente,
o mesmo conjunto de recurso.
Então tem a mesma anotação
escrita pelo desenvolvedor.
Ou vai aceitar aquela
instabilidade com a anotação
UseExperimental do Kotlin.
São duas formas válidas que não causam

English: 
yield any error from the Kotlin
compiler or our Lint rule.
So finding call-- what
are we going to do
to implement this Lint rule?
First, we're going to
find calls from Java code
only to these APIs
that are annotated.
So we'll be implementing
SourceCodeScanner again.
And like we did
for method calls,
we're going to set the
applicable annotations
this time.
So if we have a
call site that uses
an annotation or an annotation
that was itself annotated
with kotlin.Experimental, we're
going to receive a callback
to visitAnnotationUsage.
And again, because experimental
is a meta annotation--
sorry.
We'll get to that in a sec.
Because we only want to
look at Java source files,
we're going to check
if it's a Kotlin.
If it is, we're done.
If it's not, we're going
to enforce the semantics
that the Kotlin compiler uses.
And that's fairly
straightforward, right?
It's one of two things.
Either it has the exact same
annotation somewhere in scope.

Korean: 
Lint 규칙에서
오류를 발생시키지 않습니다
이제 호출 찾기입니다
이 Lint 규칙을 구현하려면
어떻게 해야 할까요
먼저 자바 코드에서
주석이 달린 API까지만
호출을 찾습니다
따라서
SourceCodeScanner를 다시 구현합니다
또한 메서드 호출에서와 같이
적용 가능한 어노테이션을
설정합니다
어노테이션 또는
kotlin.Experimental를 통해
자체 주석 처리된 어노테이션을
사용하는 호출 위치가 있다면
visitAnnotationUsage에 대한 콜백을
받게 됩니다
experimental은
메타 어노테이션이기 때문에
죄송합니다
이 부분은 잠시 후에 다루겠습니다
자바 소스 파일만 살펴보고자 하므로
Kotlin으로 작성되었는지 확인합니다
맞다면, 작업이 완료된 것입니다
그렇지 않다면
Kotlin 컴파일러에서 사용하는
의미 구조를 적용합니다
어렵지 않죠?
두 가지 중 하나입니다
하나는 scope 내에
동일한 어노테이션이 있는 경우이고

Portuguese: 
erro no Kotlin Compiler
ou na nossa regra Lint.
Encontrar chamadas...
O que faremos
para implantar essa
regra Lint?
Primeiro, vamos achar
chamadas no código Java
apenas para APIS anotadas.
Vamos implementar
SourceCodeScanner de novo.
E como fizemos para chamadas de métodos,
vamos definir as anotações
aplicáveis dessa vez.
Se tivermos um local de chamadas que usa
uma anotação ou uma anotação anotada
com kotlin.Experimental,
vamos receber um callback
para visitAnnotationUsage.
E como experimental é uma meta anotação...
Desculpe.
Falamos disso
em um segundo.
Como vamos analisar
só arquivos de fonte Java,
vamos verificar se é um Kotlin.
Se for, pronto.
Se não for, vamos aplicar a semântica
que o Kotlin Compiler usa.
E isso é bem simples, certo?
É uma de duas coisas.
Ou tem a mesma anotação
em algum lugar no escopo.
Ou será explicitamente aceita
em algum lugar no escopo.

Chinese: 
或者我们的 Lint 规则中发生任何错误
下面谈谈如何寻找调用
我们要如何实现这个 Lint 规则呢？
首先 我们要仅从 Java 代码中找到
与这些被注解的 API 对应的调用
我们要再次实现 SourceCodeScanner 了
正如我们为方法调用所做的那样
这一次 我们会设置 applicableAnnotations
如果我们的调用使用了注解
或是被 kotlin.Experimental 注解过的注解
我们就会收到一个回调 visitAnnotationUsage
因为 Experimental 是一个元注解
抱歉 这个我们等会儿再谈
因为我们只想看 Java 源文件
我们要检查一下 看它是否是 Kotlin 代码
如果是的话 就完成了
如果不是 我们就要强制执行 Kotlin 编译器使用的语法
看起来相当直截了当 对吧？
二选一
要么它在范围内的某处拥有完全相同的注解
要么就是需要在范围内部某处被显式采用

Spanish: 
Estos son dos métodos válidos
que no mostrarán ningún error
del compilador de Kotlin
ni de la regla de Lint.
Para encontrar la llamada,
¿cómo implementamos esta regla de Lint?
Primero, buscaremos
llamadas del código de Java
solo para las API que se anotaron.
Entonces, volveremos
a implementar SourceCodeScanner.
Al igual que con los métodos de llamada,
esta vez, estableceremos
las anotaciones aplicables.
Si tenemos un sitio de llamadas
que usa una anotación,
o bien una anotación
que se escribió con kotlin.Experimental, 
recibiremos una devolución de llamada
para visitAnnotationUsage.
Nuevamente, como
es una meta anotación experimental…
Lo siento, ya hablaré de eso.
Como solo queremos
ver los archivos Java fuente,
revisaremos si es de Kotlin.
Si así es, habremos terminado.
De lo contrario,
aplicaremos los elementos semánticos
que usa el compilador de Kotlin.
Es bastante directo ¿no?
Una de dos:
Tiene la misma anotación
en alguna parte del alcance,
o bien se habilita explicitamente allí.

Japanese: 
Kotlinのコンパイラやルールで
エラーは発生しません
このルールではまず
Javaからの
アノテーションが付加された
APIへの呼び出しを探します
SourceCodeScannerを実装し
applicableAnnotationsを設定します
アノテーションか
Experimentalが付いた
アノテーションを使用している場合は
visitAnnotationUsageで
コールバックを受けます
Experimentalは
メタアノテーション
いえ違いますね
Javaソースファイルが対象なので
Kotlinかどうか調べ
Kotlinでなければ
Kotlinのコンパイラの
セマンティクスを強制します
単純にそのどちらかで
スコープ内に同じ
アノテーションがあるか
スコープ内で明示的に
オプトインするかです

Indonesian: 
menghasilkan error dari
compiler Kotlin atau aturan Lint.
Jadi mencari panggilan--
apa yang perlu dilakukan
guna menerapkan aturan Lint?
Pertama, kita akan mencari
panggilan hanya dari kode Java
hingga API ini yang diberi anotasi.
Jadi, kita akan
menerapkan SourceCodeScanner lagi.
Dan seperti panggilan metode,
kali ini kita akan menetapkan
anotasi yang dapat diterapkan.
Jadi, jika ada situs
panggilan yang menggunakan
anotasi atau anotasi
yang dianotasikan sendiri
dengan kotlin.Experimental,
kita akan menerima callback
ke visitAnnotationUsage.
Sekali lagi, karena eksperimental
adalah anotasi meta--
maaf.
Akan kita bahas sesaat lagi.
Karena kita hanya ingin
mencari file sumber Java,
kita akan periksa
apa ini memang Kotlin.
Jika iya, selesai sudah.
Jika tidak,
kita akan menerapkan semantik
yang digunakan compiler Kotlin.
Cukup jelas, ya?
Ada dua kemungkinan.
Anotasinya sama persis dalam cakupan.
Atau akan secara eksplisit
masuk dalam cakupan.

Korean: 
다른 하나는 scope 내에서
어딘가로 명시적으로 선택된 경우입니다
첫 번째의 경우 experimental이
메타 어노테이션이기 때문에
experimental로
자체 주석 처리된 어노테이션이
필요합니다
usage로 반환된
어노테이션의 uastParent를
확보합니다
헷갈리네요
이게 상위 항목인지 몰랐습니다
debug point를 설정합니다
Lint 규칙을 작성하실 때
헷갈리는 부분이 있다면
debug point를 꼭 설정하세요
확인하기 위해 스택을 살펴봤는데요
여기에 제가 찾던 게 있네요
이 콜백에서 반환된 노드의
uastParent입니다
완전히 정규화된
TimeTravelExperiment 어노테이션 이름을
확보했습니다
다음으로 이게 어디에서
사용되는지 찾습니다
호출 위치 범위 내에서
주석 처리된 요소를
찾습니다
이는 UAnnotated
인터페이스를 구현함을 의미합니다
직접 호출이 될 수도 있고요
콜백을 받은 메서드 호출이거나
그 상위에 위치할 수도 있습니다
클래스일 수도 있죠
패키지 등이 될 수도 있습니다

Portuguese: 
Primeiro, como experimental é uma
meta anotação, queremos que
a anotação que é ela mesma
anotada com experimental.
Vamos obter o uastParent da anotação
que foi retornada como um uso.
Isso é confuso.
Eu não sabia que era o parent.
Defino um ponto de depuração.
Defina os pontos de depuração
se algo estiver confuso
ao escrever regras Lint.
E olhei para a pilha para ver.
Ok, aqui está o que eu esperava.
É o uastParent do nó que
foi retornado neste callback.
Obtivemos o nome da anotação
TimeTravelExperiment
totalmente qualificado.
E queremos encontrar onde foi usado.
Estamos procurando
por um elemento anotado
com o escopo
do nosso lugar de chamada.
E isso significa que implementa
a interface UAnnotated.
E isso pode ser a chamada direta.
Pode ser a chamada de método
para que recebemos callback
ou pode estar em algum lugar acima.
Pode ser a classe.
Pode ser o pacote etc.

Chinese: 
首先 因为 Experimental 是元注释
我们希望它本身是注解为 Experimental 的
我们会获取作为用例被返回的注解的 uastParent   
看上去令人迷惑
我本来其实不知道它就是母项
我设置了调试点
在编写 Lint 规则时
如果有任何地方令你感到迷惑 请务必设置调试点
我只需要看看栈
好 我想找的东西在这里
也就是返回给这个回调的节点的 uastParent
我们获取了 TimeTravelExperiment 注解名 完全合格
然后 我们想要找出它是在哪里被使用的
我们要寻找调用点范围内的带注解的元素
这意味着 它会实现 UAnnotated 接口
甚至还包括直接调用
也许是导致我们收到回调的方法调用
也许是来自上方某个层级
可能是类 可能是代码包 等等

Japanese: 
まずメタアノテーションの
Experimentalが付加された
アノテーションを探します
usageとして返されたアノテーションの
uastParentを取得しますが
親かどうか実際分かりません
こういう場合は
必ずデバッグポイントを
セットします
スタックを確認したら
このコールバックで返されたのは
ノードのuastParentでした
TimeTravelExperiment
アノテーションの
完全修飾名を取得して
使用された場所を探します
コール サイトのスコープ内で
アノテーション付きの要素を探します
UAnnotatedインターフェースを
実装していて
直接呼出やコールバックを
受け取ったメソッド呼出
またはその上のクラスなどからの
呼出の可能性があります

Spanish: 
Como la experimental
es una meta-anotación,
queremos la anotación
que se indicó
a sí misma como experimental.
Obtendremos el uastParent de la anotación
que se mostró como uso.
Es algo confuso.
Ni siquiera sabía
que era el elemento principal.
Establecí el punto de depuración.
Asegúrense de establecer
puntos de depuración si ven algo confuso
cuando escriben reglas de Lint.
Solo tienen que mirar la pila.
Bien, aquí está lo que buscaba.
Es el uastParent del nodo que se mostró
en esta devolución de llamada.
Entonces, obtuvimos el nombre
de la anotación TimeTravelExperiment,
completamente calificado.
Luego, veremos dónde se usa.
Buscaremos un elemento anotado
dentro del alcance
de nuestro sitio de llamada.
Por lo tanto, se implementa
la interfaz UAnnotated.
Y es posible que sea la llamada directa,
el método de llamada
para el que recibimos la devolución,
o bien uno superior.
Puede ser la clase,
el paquete, etcétera.

English: 
Or it's going to be explicitly
opted in somewhere in scope.
So first thing, again,
because experimental is a meta
annotation, we want the
annotation that is itself
annotated experimental.
We're going to obtain the
uastParent of the annotation
that was returned as a usage.
That's confusing.
I actually had no idea
it was the parent.
I set a debug point.
Please make sure to set debug
points if anything is confusing
when you're writing
your Lint rules.
And I just looked
at the stack to see.
OK, well, here's the
thing that I expect.
It's the uastParent
of the node that
was returned on this callback.
So we obtained the
TimeTravelExperiment annotation
name, fully qualified.
And then we want to find
out where it's used.
So we're going to be looking
for an annotated element
within the scope
of our call site.
So this means it implements
the UAnnotated interface.
And that may be the direct call.
That may be the method call that
we received the callback for,
or it may be somewhere above it.
It may be the class.
It may be the
package, et cetera.

Indonesian: 
Sekali lagi, pertama, karena
eksperimental adalah anotasi meta,
kita menginginkan
anotasi yang telah diberi
anotasi eksperimental.
Kita akan mendapatkan
uastParent dari anotasi
yang ditampilkan sebagai penggunaan.
Ini membingungkan.
Saya tidak tahu jika ini induknya.
Saya setel titik debug.
Pastikan untuk menyetel titik
debug jika ada yang membingungkan
saat menulis aturan Lint.
Saya dapat melihatnya di stack.
Oke, inilah yang saya inginkan.
uastParent dari node yang
ditampilkan di callback ini.
Kita telah mendapatkan nama
anotasi TimeTravelExperiment,
sangat memenuhi syarat.
Lalu kita ingin mengetahui
tempat digunakannya.
Jadi, kita akan mencari
elemen yang diberi anotasi
dalam cakupan situs panggilan.
Artinya, antarmuka
UAnnotated akan diterapkan.
Dan mungkin ini adalah panggilan langsung.
Mungkin panggilan metode
yang kita terima callback-nya,
atau mungkin di atasnya.
Mungkin class-nya.
Mungkin paketnya, dll.

English: 
But we're going to
start at the call site.
So here, we're getting a
callback on TimeTravelProvider.
That is the usage of an API
that was marked as experimental.
This is a UCallExpression.
So if you step through this in
the debugger, which is actually
how I wrote this slide, and you
just keep calling uastParent
on the usages or
on the node, this
is the stack that you'll see.
So we've got a
UCallExpression that
is within scope of a composite
qualified expression, in scope
of a code block expression,
in scope of a UMethod.
And the UMethod is going to
be an instance of UAnnotated,
because it has an
annotation on it.
So next we want to figure
out, what is that annotation?
So we're going to call
getAllAnnotations.
We're going to check to
see whether any of those
match the TimeTravelExperiment
annotation that we're
expecting.
And then we're going to
check whether anything was
annotated with UseExperimental.
And we're going to
extract the parameter that
was passed as the
marker class and check
that against our
feature set annotation.

Korean: 
여기에서는 호출 위치에서 시작하겠습니다
TimeTravelProvider에서 콜백을 받습니다
이는 experimental로
표시된 API의 usage입니다
이건 UCallExpression입니다
제가 슬라이드에서 소개한 것처럼
디버거에서 진행하시는 경우에
usage나 노드에서
uastParent를 계속 호출한다면
이러한 스택을 확인하실 수 있습니다
복합 정규 표현식의 scope 내,
코드 블록 표현식의 scope 내,
그리고 UMethod의 scope 내에 있는
UCallExpression이 있습니다
UMethod는
UAnnotated의 인스턴스가 됩니다
어노테이션이 있기 때문이죠
다음으로 이 어노테이션이
무엇인지 알아보겠습니다
getAllAnnotations를 호출합니다
이들 중 우리가 예상하는
TimeTravelExperiment와
일치하는 것이 있는지
확인해보겠습니다
그리고 나서 UseExperimental로
주석 처리된 것이 있는지
확인하겠습니다
먼저 marker class로
전달된 매개변수를 추출하고
feature set 어노테이션과
대조해보겠습니다

Japanese: 
まずはコール サイトです
TimeTravelProviderは
Experimental付きのAPIで
UCallExpressionです
デバッガでステップスルーすると
usageかnodeで
uastParentを呼び出し続けます
UCallExpression
UComposite
QualifiedExpression
UCodeBlockExpression
UMethodという階層で
UMethodはアノテーション付きなので
UAnnotatedのインスタンスです
次にgetAllAnnotationsを呼び出し
TimeTravelExperiment
アノテーションと
一致するかどうかを確かめ
次にUseExperimentalが
付いているか確かめます
markerClassとして
渡されたパラメータを
フィーチャーセットの
アノテーションと
突き合わせます

Chinese: 
我们要从调用点出发
我们在 TimeTravelProvider 这里获得了回调
它属于被标记为 Experimental 的 API 用例
这里是 UCallExpression
如果你在调试器里对它进行单步调试
顺便说一句 这张幻灯片就是这样写出来的
而你连续针对用例或节点调用 uastParent
那么你就会看到这样的栈
我们得到了一个 UCallExpression
它位于一个复合合格表达式的范围内
且位于一个代码块范围内 并且位于 UMethod 范围内
而 UMethod 则会成为 UAnnotated 的一个实例
因为它上面有一个注解
下面我们要弄明白的是 那个注解是什么？
我们调用一下 getAllAnnotations
看看其中有没有能够符合
我们所期待的 TimeTravelExperiment 注解的
然后我们会查看 有没有什么东西是
被 UseExperimental 注解过的
我们要提取那些作为标记类被传入的参数
并用它们来对比我们的功能集注解

Portuguese: 
Mas vamos começar no lugar da chamada.
Aqui recebemos um callback
no TimeTravelProvider.
Esse é o uso de uma API
que foi marcada como experimental.
Isso é uma
UCallExpression.
Se você se deparar com isso no depurador,
que foi como escrevi esse slide,
e continuar chamando uastParent
nos usos ou no nó,
essa é a pilha que verá.
Então temos uma UCallExpression que
está no escopo de uma
UCompositeQualifiedExpression
no escopo de uma UCodeBlockExpression
no escopo de um UMethod.
E o UMethod vai ser uma
instância de UAnnotated
porque ele tem uma anotação nele.
E depois queremos descobrir,
o que é essa anotação?
Então vamos chamar getAllAnnotations.
Vamos verificar se uma delas
corresponde à anotação
TimeTravelExperiment
que estamos esperando.
E então vamos verificar se algo foi
anotado com UseExperimental.
E vamos extrair o parâmetro passado
como a classe marcadora e verificar
se tem nossa anotação
de conjunto de recurso.

Indonesian: 
Namun kita akan mulai di situs panggilan.
Di sini, ada callback
untuk TimeTravelProvider.
Ini adalah penggunaan API yang
ditandai sebagai eksperimental.
Ini adalah UCallExpression.
Jika menggunakannya di
debugger, dan begitulah
saya menulis slide ini, dan
kalian tetap memanggil uastParent
di penggunaan atau node,
inilah stack yang muncul.
Jadi, ada UCallExpression yang
berada dalam cakupan ekspresi
composite yang memenuhi syarat,
dalam cakupan ekspresi UCodeBlock,
dalam cakupan UMethod.
Dan UMethod akan
menjadi instance UAnnotated,
karena memiliki anotasi.
Selanjutnya, kita ingin tahu,
anotasi apa itu?
Jadi kita akan
memanggil getAllAnnotations.
Kita akan memeriksa apa ada yang
cocok dengan anotasi
TimeTravelExperiment yang
diinginkan.
Lalu, kita akan memeriksa apa ada
yang diberi anotasi UseExperimental.
Dan kita akan mengambil parameter yang
diteruskan sebagai
class penanda dan memeriksanya
terhadap anotasi kumpulan fitur.

Spanish: 
Pero comenzaremos en el sitio de llamada.
Aquí, recibiremos
una devolución en TimeTravelProvider.
Ese es el uso de una API
que se marcó como experimental.
Es un UCallExpression.
Si lo procesamos con el depurador,
como lo hice en esta diapositiva,
y seguimos llamando a uastParent
en los usos o el nodo,
veremos esta pila.
Si tenemos un UCallExpression
dentro del alcance de una expresión
de un compuesto calificado,
en el de una expresión
de bloqueo de código, en el de un UMethod.
El UMethod será una instancia
de UAnnotated
porque tiene una anotación.
Luego, averiguaremos qué es esa anotación.
Para eso, llamaremos a getAllAnnotations
y revisaremos si alguna coincide
con la anotación TimeTravelExperiment
que buscamos.
Y, luego, veremos si se anotó algo
con UseExperimental.
Extraeremos el parámetro
que se pasó como clase de marcador
y lo analizaremos con nuestra
anotación de conjunto de funciones.

Spanish: 
Si alguno da valor "true",
habremos terminado.
Si no, obtenemos el elemento principal
y seguimos recorriendo el alcance.
Vemos nuestro método, nuestra clase,
luego el paquete, etcétera.
Por último, aquí está
el resultado que obtendrían
si ejecutan la regla de Lint
en la línea de comandos.
Este es un mal uso.
Deben habilitarlo, o bien
marcarlo explícitamente como experimental.
Bien, sugerencias básicas
para escribir reglas de Lint.
Una de las cosas más útiles
que hacemos Rahul y yo
es mirar el código fuente oficial de Lint.
Creamos un vínculo corto a él;
la URL real de Git es demasiado larga.
Pero aquí están
todas las reglas de Lint que conocen.
De hecho, modelé el detecto experimental
en función del nuevo detector de API
para ver cómo funciona el alcance
dentro de las reglas de Lint.
Como mencioné antes,
adjuntar el depurador a las pruebas
es muy conveniente.
Ahora, el caso de error de Lint.
Hay algún error en uno
de sus archivos fuente o en su regla,

Portuguese: 
Então se uma dessas for verdade,
estamos prontos.
Se não for, vamos pegar o parent
e continuar transferindo
até o escopo.
Então analisamos nosso método.
E então, nossa classe.
E então olhamos para nosso pacote etc.
E no final, aqui está
a resposta que você recebe da execução
da regra Lint na linha de comando.
Ela diz,
esse uso é ruim.
Você precisa aceitar ou
precisa marcar como explicitamente
aceita em experimental.
Tudo bem, algumas dicas básicas
para escrever regras Lint.
Uma das coisas mais úteis
que Rahul e eu usamos
muito é consultar
o código fonte oficial do Lint.
Então criamos um pequeno link.
O Get URL real é super longo.
Mas aqui que estão todas
as regras Lint que você conhece.
Na verdade, modelei
o detector experimental
com base no novo detector
de API para descobrir como
o escopo funciona
dentro das regras Lint.
Como já disse, anexar o depurador
aos casos de teste
pode ser incrivelmente útil.
O caso de falha para
o Lint agora,
se tiver algo errado com um dos
arquivos de fonte ou com sua regra,
é retornar nenhum aviso,

English: 
So if either of those
is true, we're done.
If it wasn't, we're
going to get the parent
and keep traversing
up the scope.
So we're looking at our method.
Then we're looking at our class.
Then we're looking at
our package, et cetera.
And at the end of
the day, here's
the output that you would
get from running the Lint
rule on the command line.
This usage is bad.
Either you need
to opt in, or you
need to mark it as explicitly
opted into experimental.
All right, so some basic
tips for writing Lint rules.
One of the most useful
things that Rahul and I use
extensively is just looking at
the official Lint source code.
So we made a short link for it.
The real Git URL is super long.
But this is where
all of the Lint
rules that you're
familiar with are.
And in fact, I modeled
the experimental detector
after the new API
detector to figure out how
scope works within Lint rules.
As I mentioned also, attaching
the debugger to your test cases
can be incredibly useful.
The failure case
for Lint right now--
if you have something wrong
with one of your source
files or something
wrong with your rule--
is often just return
no warnings, which

Chinese: 
如果有一项检查得出了肯定结论 工作就完成了
如果没有得出肯定结论 我们就要找到母项
并继续在整个范围内部向上搜索
首先观察我们的方法 然后观察类 然后观察代码包 等等
最后 这里是你在命令行模式下运行 Lint 规则
得到的输出
这个用法不太好
你需要选择采用 或是将其标记为
显式使用 Experimental
在编写 Lint 规则时 要注意遵守以下要点
我和 Rahul 最常用也是最有用的一个东西就是
多看官方 Lint 源代码
我们为它制作了一个短链接
原版的 Git 链接很长
大家熟悉的 Lint 规则都在这里
而且 我还基于新 API 侦测器
为 Experimental 侦测器进行了建模
以便探明 Lint 规则内范围的工作原理
如我所说 把调试器附加到你的测试用例中 用处很大
目前 Lint 的失败案例是
如果你的源文件或规则出了问题
导致常常不返回报警信息 让你无法获得任何信息

Indonesian: 
Jika ada yang benar, selesai sudah.
Jika tidak, kita akan panggil induknya
dan terus memeriksa cakupan.
Kita periksa metodenya.
Kita periksa class.
Lalu kita periksa paket, dll.
Dan pada akhirnya,
inilah output yang akan
didapat dari menjalankan
aturan Lint di command line.
Penggunaan ini buruk.
Kalian perlu ikut serta,
atau menandainya sebagai
secara eksplisit masuk eksperimental.
Baiklah, tips dasar
dalam menulis aturan Lint.
Salah satu yang paling
berguna yang saya dan Rahul gunakan
secara menyeluruh yakni
melihat kode sumber Lint resmi.
Jadi kami sudah sediakan link singkatnya.
URL Git sebenarnya sangat panjang.
Namun, di sinilah
semua aturan Lint
yang kalian kenal berada.
Bahkan, saya
merancang detektor eksperimental
setelah detektor API
yang baru untuk mencari tahu
cara cakupan berfungsi dalam aturan Lint.
Seperti yang saya sebutkan,
melampirkan debugger ke kasus penggunaan
akan sangat berguna.
Kasus kegagalan untuk Lint saat ini--
jika terjadi error
di salah satu file sumber
atau aturan kalian--
sering kali tidak
menampilkan peringatan,

Japanese: 
真ならそれで終了し
偽なら親を取得して
上のスコープに移動します
メソッドを見たら
次はクラス
その次はパッケージというようにです
コマンドラインで
Lintを実行すると
この使用法は不適切で
オプトイン
または明示的に
Experimentalにせよと指示されます
Lintのルールを作成するうえで
一番役に立つのは
公式のソースコードを眺めることです
こちらがリンクで
長すぎるので縮めています
Lintルールが網羅されています
今回も新しいAPIのDetectorを
スコープを理解する参考にしました
デバッガをテストケースに
アタッチしましょう
Lintはソースファイルの不具合や
ルールに間違いがあっても
警告を返さないので

Korean: 
이 중 하나가 true라면
여기에서 완료됩니다
그렇지 않다면 상위 항목을 찾아
scope 전체를 계속 순회합니다
여기 메서드가 있습니다
클래스가 있고요
패키지 등이 있습니다
그리고 여기에는
명령줄에서
Lint 규칙을 실행하면 얻게 되는
아웃풋이 있습니다
이 usage는 좋지 않네요
이대로 두거나
experimental을 명확히
사용하는 것으로 표시합니다
이상으로 Lint 규칙 작성에
대한 기본 팁을 알아보았습니다
라훌과 제가 주로 사용하는
가장 유용한 방법 중 하나는
공식 Lint 소스 코드를
살펴보는 것입니다
여기에 짧은 링크가 있습니다
실제 Git URL은 엄청 깁니다
익숙하신 모든 Lint 규칙을
확인하실 수 있습니다
저는 Lint 규칙 내에서
scope가 어떻게 작동하는지 파악하기 위해
새로운 API 감지기를 모델로
experimental 감지기를 만들었습니다
이전에 말씀드렸듯이
디버거를 테스트 사례와
연관시키는 것은 매우 유용합니다
소스 파일 중 하나에 문제가 있거나
규칙에 문제가 있는 경우
Lint가 제대로 작동하지 않더라도
경고가 반환되지 않기 때문에

Portuguese: 
o que dá zero informação.
Então defina um ponto de interrupção
na sua regra Lint.
E execute seu Lint...
execute o teste em modo de depuração.
E receberá um ponto de
interrupção na regra Lint.
Você pode esperar os nós de UAST.
É mais fácil com classes Java,
porque tudo está pré-preenchido.
Se executar Kotlin, tudo será
iniciado lentamente.
E você não tem sourceToString
quando estiver depurando.
É mais fácil com casos de teste Java.
E finalmente, PSI Viewer é algo
que pode ser ativado se procurar por ele.
Ele permite, sem ter que
executar o depurador,
inspecionar a árvore PSI
de um arquivo específico.
Tudo bem,
temos 30 segundos ainda.
Então vou falar super rápido.
TDDR...
Baselines vão permitir
que você ative uma regra
Lint que tem milhares
de violações de uma vez.
Você pode definir um arquivo
baseline nas opções do Lint.
Quando você executar gradlew lintDebug,
este arquivo baseline será gerado.
E todos os novos avisos que tiver

Spanish: 
pero no se muestran advertencias,
por lo que no tienen esa información.
Establezcan un punto de interrupción
en la regla de Lint,
y, luego, ejecuten la prueba
en modo de depuración.
Así, se establecerá el punto en la regla
y pueden esperar
que aparezcan los nodos UAST.
El proceso es más fácil
con las clases Java
porque todo se completa automáticamente.
En Kotlin,
todo tiene inicialización diferida,
por lo que no obtendrán dos strings fuente
cuando hagan la depuración.
Por eso es más fácil
con las pruebas de Java.
Finalmente, si lo buscan,
pueden habilitar el visor de PSI
Este les permite inspeccionar
el árbol PSI de un grarchivo
sin ejecutar el depurador.
Bien, quedan 30 segundos.
Explicaré esto muy rápido.
Las referencias TLDR
les permiten habilitar una regla de Lint
con miles de infracciones simultáneas.
Pueden establecer un archivo de referencia
en las opciones de Lint
y, cuando ejecuten gradlew lintDebug,
este se generará.
Entonces, se suprimirán

Chinese: 
所以 请在你的 Lint 规则内设置一个断点
然后 在调试模式下运行测试
你会在 Lint 规则内获得一个断点
并获取一些 UAST 节点
这项工作在 Java 类中更容易完成
因为所有东西都是预先填充好的
如果你运行的是 Kotlin 所有东西只会进行最基本的初始化
你在调试的时候无法获得和资源对应的字符串
所以 在 Java 中测试 难度更低
最后 在搜索之后 你可以启用 PSI Viewer
在它的帮助下 你甚至无需运行调试器
就可以检视某个指定文件的 PSI 代码树
好 时间还剩下30秒
所以我会讲得超级快
简而言之 baseline 允许你使用一个内含数千个规则的 Lint
你可以在 Lint 选项中设置 baseline 文件
当你运行 gradlew lintDebug 的时候
它就会生成这个 baseline 文件
任何新收到的警告信息都会被“静音”

Indonesian: 
jadi, kalian
tidak mendapat informasi.
Maka, tentukan titik henti sementara
dalam aturan Lint.
Lalu, jalankan Lint--
jalankan tes dalam mode debug.
Akan ada titik henti sementara
di aturan Lint.
Kalian bisa mengharapkan node UAST.
Ini akan lebih mudah dengan class Java,
karena semuanya telah diisi.
Jika menjalankan Kotlin,
semuanya dimulai dengan lambat.
Dan tidak ada sumber dua
string saat melakukan debugging.
Jadi, akan lebih mudah
dengan kasus pengujian Java.
Dan terakhir, penampil PSI
dapat diaktifkan jika kalian mencarinya.
Ini memungkinkan kalian,
tanpa menjalankan debugger,
memeriksa pohon PSI dari file tertentu.
Baik, tersisa 30 detik lagi.
Saya akan membahas ini dengan cepat.
TLDR--dasar pengukuran
akan memungkinkan kalian
mengaktifkan aturan
Lint yang berisi ribuan
pelanggaran sekaligus.
Kalian bisa tetapkan
file dasar pengukuran di opsi Lint.
Saat menjalankan gradlew lintDebug,
yang akan menghasilkan file baseline.
Semua peringatan baru kalian
akan ditahan, artinya jika

English: 
gives you zero information.
So set a breakpoint
within your Lint rule.
And then run your Lint--
run the test in debug mode.
And you'll get a breakpoint
in your Lint rule.
You can expect the UAST nodes.
This is easier
with Java classes,
because everything
is pre-populated.
If you run Kotlin, everything
is lazily initialized.
And you don't get source two
strings when you're debugging.
So it's easier with
Java test cases.
And finally, PSI
viewer is something
that you can enable
if you search for it.
This lets you, without even
having to run the debugger,
inspect the PSI tree
of a given file.
All right, we have
30 seconds left.
So I'm going to go
through this super quick.
TLDR-- baselines
are going to allow
you to enable a Lint
rule that has thousands
of violations at once.
You can set a baseline
file in your Lint options.
When you run gradlew
lintDebug, it
will generate this
baseline file.
And any new warnings
that you have

Japanese: 
何も情報が得られません
ルール内に
ブレークポイントを設定して
デバッグモードでテストすれば
UASTノードが得られます
Javaクラスの方が
事前に初期化されるので簡単です
Kotlinは初期化が緩いので
Javaのテストケースの方が楽です
PSI Viewerを有効化すると
デバッガを実行しなくても
ファイルのPSIツリーを検査できます
残り時間もわずかなので
ごく簡単に説明します
ベースラインがあれば
一度に大量の違反がある
ルールを作成できます
オプションで
ベースラインファイルを設定できます
gradlew lintDebugを
実行すると生成され
新たな警告があっても無視されます

Korean: 
정보를 얻을 수 없습니다
따라서 Lint 규칙에
breakpoint를 설정하시기 바랍니다
그런 다음 Lint를 실행하시고
디버그 모드에서 테스트를 실행하시면
Lint 규칙에
breakpoint가 생깁니다
UAST 노드를 예상하실 수 있습니다
자바 클래스를 사용하면 더 쉽습니다
모든 것이 미리 채워지기 때문이죠
Kotlin을 실행하시면 초기 설정이 느립니다
디버깅할 때 소스를
문자열로 변환할 수 없습니다
따라서 자바 테스트 사례를
사용하면 더 쉽습니다
마지막으로 PSI 뷰어는
PSI를 검색하는 경우
사용 설정할 수 있습니다
디버거를 실행하지 않고도
특정 파일에서
PSI 트리를 검사할 수 있습니다
이제 30초 남았네요
아주 빠르게 진행하겠습니다
베이스라인을 사용하면
위반 수가 수천 개인 Lint 규칙을
한번에 사용 설정할 수 있습니다
Lint 옵션에서
baseline file을 설정할 수 있습니다
gradlew lintDebug을 실행하면
이렇게 baseline file이 생성됩니다
새로운 경고가 있으면

Chinese: 
也就是说 如果你想让它们发挥作用的话
它们仍然会显示在 IDE 中
不过 你真正需要开启的是 isAbortOnError
在生成了 baseline 之后
它意味着任何新出现的违规操作都将失败
如果你在将持续整合作为预先提交的验证更改代码来运行
这个方法非常适合用来预防出现新的错误
最后 还有一分钟时间来介绍额外的参考资料
我们在 Rahul 的 GitHub 页面上备好了
与本次演讲相关的所有代码
也请大家查看官方推出的 Lint Check 源代码
我们为之前的几年总结了两套超棒的演示文稿
Matthew Gharrity 去年在 ADS 的演讲
纵览了在项目中使用 Lint 的技巧
Tor Norbye 在 KotlinConf 上的演讲
从底层出发 解释了 Lint 静态分析的工作原理
此外 Lint-Dev Google Group 
也可以帮助大家从 Tor 和 Matthew 那里获取帮助
Rahul 和我也会在那里出现
那是一个互助气氛很浓的社区
致力于研究解决 Lint 规则

Japanese: 
これを役立てるには
IDEには表示されますが
isAbortOnErrorを
trueにします
ベースラインを生成すると
新たな違反は無視されるので
継続的インテグレーションなら
変更確認で新たな
エラーが出るのを防げます
最後に関連資料を紹介します
ラフルのGitHubに
今回のソースがあります
公式Lintチェックで
ソースコードを確認できます
プレゼンテーションも
２つあります
マシュー･ギャリティは
プロジェクトでのLintの使用を概説
トール･ノルビーは
Lintでの静的解析の仕組みを
詳しく解説しています
Lint-dev Googleグループで
彼らの助言が得られます
私たちも参加しています
みな協力的なので
難しい問題の解決策が

Portuguese: 
serão suprimidos, o que significa que
se você quiser que sejam úteis,
ainda serão mostrados no IDE,
mas é recomendável ativar isAbortOnError.
Depois de gerar seu baseline,
isso significa que todas
as nova violações falharão.
Se estiver executando
integração contínua
como pré-envio
para verificar mudanças,
isso é ótimo para evitar
adição de novos erros.
E por fim, faltando um minuto,
recursos adicionais.
Temos o código fonte no GitHub
do Rahul para tudo
que vimos nesta apresentação.
Confiram o código fonte do
oficial LintCheck.
Temos duas ótimas apresentações
dos anos anteriores.
A do Matthew Gharrity na
conferência de 2018
é uma ótima visão geral do
uso do Lint no seu projeto.
A do Tor Norbye na KotlinConf
é uma explicação bem detalhada
de como a análise estática
funciona no Lint.
E o Grupo do Google Lint-dev
pode ser útil para conseguir
ajuda do Tor e Matthew.
E Rahul e eu também estaremos lá.
É uma ótima comunidade de apoio
para trabalhar com regras Lint
e responder algumas

Spanish: 
las nuevas advertencias que vean,
por lo que si quieren que sean útiles…
es decir, todavía están en el IDE,
pero queremos activar isAbortOnError.
Una vez que generen la referencia,
mostrarán error
todas las infracciones nuevas.
Ejecutar la integración continua
como envío previo para verificar cambios
es un gran manera de impedir
que aparezcan nuevos errores.
Por último, les mostraré
más recursos este último minuto.
Tenemos el código fuente
en el GitHub de Rahul.
Allí verán el contenido de esta presentación.
Consulten
el código fuente oficial de Lint Check.
Tenemos dos presentaciones geniales
de años anteriores.
La charla de Matthew Gharrity
sobre ADS del año pasado
es un gran resumen
sobre implementación de Lint en proyectos.
La de Tor Norbye sobre KotlinConf
es una explicación muy sencilla
de cómo funciona
el análisis estático en Lint.
Y en el grupo Lint-dev Google,
pueden obtener ayuda de Tor y Matthew.
Rahul y yo también estamos ahí.
Es una gran comunidad de ayuda
para trabajar en reglas de Lint

English: 
will be suppressed,
which means if you
want these to be useful--
they're still shown in the IDE--
but you really want to
turn on isAbortOnError.
Once you've generated
your baseline,
this means any new
violations will fail.
So if you're running
continuous integration
as maybe pre-submit
for verifying changes,
that's a great way to prevent
new errors from being added.
And finally, with one minute
remaining, further resources.
We've got the source code on
Rahul's GitHub for everything
that you saw in
this presentation.
Please check out the official
Lint Check source code.
We've got two
awesome presentations
from previous years.
Matthew Gharrity's
talk from ADS last year
is a good high level overview
of using Lint in your project.
Tor Norbye's talk
from KotlinConf
is a really low
level explanation
of how static analysis
works in Lint.
And then the
Lint-dev Google Group
can be very useful for getting
some help from Tor and Matthew.
And Rahul and myself will
also make an appearance there.
So it's a great
supportive community
for working on Lint rules and
answering some of your more

Korean: 
무시됩니다
경고가 유용하다고 생각되는 경우
IDE에서 확인할 수 있습니다
그래도 isAbortOnError를
사용하시는 게 좋을 겁니다
baseline이 생성되었다는 것은
새로운 위반 사항이
있을 경우 실패한다는 의미입니다
변경 사항을 확인하기 위한 사전 제출로
지속적인 통합을 실행하시는 것도
새로운 오류가 추가되지
않게 하는 좋은 방법입니다
남은 1분 동안
추가 리소스를 설명하겠습니다
라훌의 GitHub에서
오늘 발표에서 다룬
모든 것에 대한
소스 코드를 확인하실 수 있습니다
공식 Lint Check
소스 코드를 확인하시기 바랍니다
저희는 최근 몇 년간
정말 멋진 발표 두 개를 진행했습니다
작년 ADS에서 매튜 개리티는
프로젝트에서 Lint를 사용하는 것에 관한
유용한 내용을 소개하셨습니다
토르 노르비는 KotlinConf에서
Lint의 정적 분석 작동 방식에 대해
아주 자세하게 설명하셨죠
Lint-dev Google Group은
토르와 매튜로부터
도움을 받는 데 매우 유용합니다
라훌과 저도 참여합니다
Lint 규칙을 연구하고
어려운 문제에 대한 해답을 제공하는

Indonesian: 
ingin agar ini berguna--
peringatan masih muncul di IDE--
namun, kalian mau
mengaktifkan isAbortOnError.
Setelah membuat dasar pengukuran,
artinya semua pelanggaran baru akan gagal.
Jika menjalankan integrasi berlanjut
mungkin sebagai pra-pengiriman
untuk memverifikasi perubahan,
ini adalah cara bagus untuk mencegah
agar error baru tidak ditambahkan.
Terakhir, dengan satu
menit tersisa, resource lanjutan.
Tersedia kode sumber
dari GitHub Rahul untuk semua
yang kalian lihat di presentasi.
Bukalah kode sumber Lint Check yang resmi.
Ada dua presentasi menarik
dari tahun sebelumnya.
Diskusi Matthew Gharrity
dari ADS tahun lalu
adalah ringkasan yang sangat baik
untuk penggunaan Lint dalam project.
Diskusi Tor Norbye dari KotlinConf
adalah penjelasan sederhana tentang
cara analisis statis berfungsi di Lint.
Google Grup Lint-dev
dapat berguna untuk
mendapatkan bantuan dari Tor dan Matthew.
Saya dan Rahul juga akan ada di sana.
Komunitas ini sangat mendukung
dalam pengerjaan
aturan Lint dan akan menjawab

Portuguese: 
perguntas mais difíceis.
Então obrigado, pessoal.
[MÚSICA]

English: 
difficult questions.
So thank you, everybody.
[MUSIC PLAYING]

Indonesian: 
pertanyaan yang sulit.
Terima kasih semuanya.
[SUARA MUSIK]

Chinese: 
并回答大家提出的较为复杂的问题
谢谢大家

Japanese: 
見つかるかもしれません
ありがとうございました
[音楽]

Korean: 
매우 유용한 커뮤니티입니다
감사합니다
[음악 재생]

Spanish: 
y responder algunas
de las preguntas más difíciles.
Bien, gracias a todos.
