<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">
	<channel>
		<title>Author at Infinum</title>
		<atom:link href="https://infinum.com/blog/author/sven-vidak/feed/" rel="self" type="application/rss+xml" />
		<link></link>
		<description>Building digital products</description>
		<lastBuildDate>Tue, 14 Apr 2026 10:32:35 +0000</lastBuildDate>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>

					<item>
				<image>
					<url>7859https://infinum.com/uploads/2019/06/how-to-test-custom-lint-checks-0.webp</url>
				</image>
				<title>How to Test Custom Lint Checks</title>
				<link>https://infinum.com/blog/how-to-test-custom-lint-checks/</link>
				<pubDate>Thu, 27 Jun 2019 09:30:00 +0000</pubDate>
				<dc:creator>Sven Vidak</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/how-to-test-custom-lint-checks/</guid>
				<description>
					<![CDATA[<p>Tests help make sure the check behaves correctly in every possible case, but can also help with debugging.</p>
<p>The post <a href="https://infinum.com/blog/how-to-test-custom-lint-checks/">How to Test Custom Lint Checks</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-182"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-92">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-95"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-93">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-94'
	>
	In my previous article, I’ve talked about <a href="https://infinum.com/blog/what-is-android-lint-and-how-helps-write-maintainable-code/">writing Lint checks</a> and benefits they can bring to your project. I’ve also outlined how to write custom Lint checks, but I didn’t cover how to test them. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-98"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-96">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-97'
	>
	Of course, you can always observe if Lint reports an error or warning if you make a mistake, but the problem arises if you have a bug in your implementation.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-101"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-99">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-100'
	>
	Tests help make sure the check behaves correctly in every possible case, but can also help with debugging.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-104"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-102">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-103'
	>
	Dependencies</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-107"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-105">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-106'
	>
	First step is to add test dependencies in your module’s <code>build.gradle</code> file:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-109"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-groovy github-light" data-language="groovy" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">testImplementation </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">com.android.tools.lint:lint:</span><span class="token" style="color: #24292e;">$l</span><span class="token" style="color: #24292e;">i</span><span class="token" style="color: #24292e;">n</span><span class="token" style="color: #24292e;">t</span><span class="token" style="color: #24292e;">V</span><span class="token" style="color: #24292e;">e</span><span class="token" style="color: #24292e;">r</span><span class="token" style="color: #24292e;">s</span><span class="token" style="color: #24292e;">i</span><span class="token" style="color: #24292e;">o</span><span class="token" style="color: #24292e;">n</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">testImplementation </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">com.android.tools.lint:lint-tests:</span><span class="token" style="color: #24292e;">$l</span><span class="token" style="color: #24292e;">i</span><span class="token" style="color: #24292e;">n</span><span class="token" style="color: #24292e;">t</span><span class="token" style="color: #24292e;">V</span><span class="token" style="color: #24292e;">e</span><span class="token" style="color: #24292e;">r</span><span class="token" style="color: #24292e;">s</span><span class="token" style="color: #24292e;">i</span><span class="token" style="color: #24292e;">o</span><span class="token" style="color: #24292e;">n</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-112"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-110">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-111'
	>
	<code>lintVersion</code> is defined in the same way as in the previous article – <code>gradlePluginVersion + 23.0.0</code>. At the moment of writing, it would be <code>26.4.0</code>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-115"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-113">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-114'
	>
	Basic test class</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-118"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-116">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-117'
	>
	Lint checks are tested with the JUnit framework. The only part that’s a bit different is that your class must extend <code>LintDetectorTest</code> class which will force you to specify detector and issues you want to test. In the <a href="https://infinum.com/blog/what-is-android-lint-and-how-helps-write-maintainable-code/">previous article</a>, I’ve defined all components that one Lint check has to have. I’ll use those here.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-121"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-119">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-120'
	>
	When you extend <code>LintDetectorTest</code> class, you’ll have to implement two methods: <code>getDetector</code> and <code>getIssues</code>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-123"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">class CorrectClickListenerDetectorTest </span><span class="token">: </span><span class="token" style="color: #6f42c1;">LintDetectorTest</span><span class="token">() {
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">fun getDetector</span><span class="token">() </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">CorrectClickListenerDetector</span><span class="token">()
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">fun getIssues</span><span class="token">() </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">listOf</span><span class="token">(ISSUE_CLICK_LISTENER)
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-126"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-124">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-125'
	>
	For each test, you’ll need a code sample that Lint will analyze. You can define those in any way you want (as a variable, read from file, etc.), but have in mind there are differences when it comes to Java and Kotlin.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-129"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-127">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-128'
	>
	Java code sample must be syntactically correct. For example, you can call non-existing methods on any object and you don’t have to specify imports for used classes, but parenthesis, keywords, etc. must be correct.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-131"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token">val </span><span class="token">incorrectMethodCallJava </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;&quot;&quot;</span><span class="token" style="color: #032f62;">
</span></span><span class="line"><span class="token" style="color: #032f62;">    public class Test {
</span></span><span class="line"><span class="token" style="color: #032f62;">        private static String s1 = &quot;Test string 1&quot;;
</span></span><span class="line"><span class="token" style="color: #032f62;">        private static String s2 = &quot;Test string 2&quot;;
</span></span><span class="line"><span class="token" style="color: #032f62;">
</span></span><span class="line"><span class="token" style="color: #032f62;">        public static void main(String[] args) {
</span></span><span class="line"><span class="token" style="color: #032f62;">            s1.setOnClickListener();
</span></span><span class="line"><span class="token" style="color: #032f62;">            s2.trim();
</span></span><span class="line"><span class="token" style="color: #032f62;">        }
</span></span><span class="line"><span class="token" style="color: #032f62;">     }
</span></span><span class="line"><span class="token" style="color: #032f62;">    </span><span class="token" style="color: #032f62;">&quot;&quot;&quot;</span><span class="token">.trimIndent</span><span class="token">()
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-134"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-132">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-133'
	>
	As you can see, there are no imports and we call <code>setOnClickListener</code> on a <code>String</code> object which does not make any sense, but Lint is cool with that.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-137"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-135">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-136'
	>
	On the other hand, when defining a Kotlin sample code, you have to make sure that the code will compile if you copy it into a real project. Since we are testing method calls on Android <code>View</code>, you have to specify import statement for the <code>View</code> class and somehow obtain instance of that class so you can call a method on it. Luckily, we don’t have to drag beloved <code>Context</code> to our test – it’s enough to have a method that takes a <code>View</code> instance as a parameter.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-139"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token">val </span><span class="token">incorrectMethodCallKotlin </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;&quot;&quot;</span><span class="token" style="color: #032f62;">
</span></span><span class="line"><span class="token" style="color: #032f62;">    import android.view.View
</span></span><span class="line"><span class="token" style="color: #032f62;">    class Test {
</span></span><span class="line"><span class="token" style="color: #032f62;">        fun main(view: View) {
</span></span><span class="line"><span class="token" style="color: #032f62;">            view.setOnClickListener { }
</span></span><span class="line"><span class="token" style="color: #032f62;">        }
</span></span><span class="line"><span class="token" style="color: #032f62;">    }
</span></span><span class="line"><span class="token" style="color: #032f62;">  </span><span class="token" style="color: #032f62;">&quot;&quot;&quot;</span><span class="token">.trimIndent</span><span class="token">()
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-142"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-140">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-141'
	>
	Have in mind that having import statement in the code sample does not require you to include Android SDK as a testing dependency – all dependencies you need are the two mentioned at the beginning of the article.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-145"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-143">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-144'
	>
	First test</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-148"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-146">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-147'
	>
	Each test is defined as a method annotated with <code>@Test</code> (same as any other JUnit test), It’s written as a chain of commands that tells Lint what to analyze, and what assertions to test.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-150"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6f42c1;">@Test</span><span class="token">
</span></span><span class="line"><span class="token">fun incorrectMethodUsage_shouldReportAWarning</span><span class="token">() {
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> obtain Lint analyzer</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">lint</span><span class="token">()
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> give it a list of files to analyze</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">.files</span><span class="token">(</span><span class="token">java</span><span class="token">(incorrectMethodCallJava))
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> run analyzer</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">.run</span><span class="token">()
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> make assertions</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">.expectWarningCount</span><span class="token">(</span><span class="token" style="color: #005cc5;">1</span><span class="token">)
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-153"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-151">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-152'
	>
	Kotlin file(s) can be analyzed in the same way, you just have to pass <code>kotlin(incorrectMethodCallKotlin)</code> as a parameter to <code>files</code> method.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-156"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-154">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-155'
	>
	More assertions</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-159"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-157">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-158'
	>
	In the previous article, I’ve defined a quick fix option for a check. Lint testing API allows you to test if the fix works.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-161"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token">val </span><span class="token">correctMethodCallJava </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;&quot;&quot;</span><span class="token" style="color: #032f62;">
</span></span><span class="line"><span class="token" style="color: #032f62;">    public class Test {
</span></span><span class="line"><span class="token" style="color: #032f62;">      private static String s1 = &quot;Test string 1&quot;;
</span></span><span class="line"><span class="token" style="color: #032f62;">      private static String s2 = &quot;Test string 2&quot;;
</span></span><span class="line"><span class="token" style="color: #032f62;">
</span></span><span class="line"><span class="token" style="color: #032f62;">      public static void main(String[] args) {
</span></span><span class="line"><span class="token" style="color: #032f62;">          s1.setThrottlingClickListener();
</span></span><span class="line"><span class="token" style="color: #032f62;">          s2.trim();
</span></span><span class="line"><span class="token" style="color: #032f62;">      }
</span></span><span class="line"><span class="token" style="color: #032f62;">    }
</span></span><span class="line"><span class="token" style="color: #032f62;">&quot;&quot;&quot;</span><span class="token">.trimIndent</span><span class="token">()
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6f42c1;">@Test</span><span class="token">
</span></span><span class="line"><span class="token">fun fix_shouldUseCorrectClickListener</span><span class="token">() {
</span></span><span class="line"><span class="token">    </span><span class="token">lint</span><span class="token">()
</span></span><span class="line"><span class="token">        </span><span class="token">.files</span><span class="token">(</span><span class="token">java</span><span class="token">(incorrectMethodCallJava))
</span></span><span class="line"><span class="token">        </span><span class="token">.run</span><span class="token">()
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> check that the fix produces the same code as the one given as a second parameter</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">.checkFix</span><span class="token">(</span><span class="token" style="color: #005cc5;">null</span><span class="token">, </span><span class="token">java</span><span class="token">(correctMethodCallJava))
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-164"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-162">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-163'
	>
	Also, you can match exact output of your check.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-166"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token">val </span><span class="token">incorrectMethodCallWarning </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;&quot;&quot;</span><span class="token" style="color: #032f62;">
</span></span><span class="line"><span class="token" style="color: #032f62;">    src/Test.java:6: Warning: Use setThrottlingClickListener [UnsafeClickListener]
</span></span><span class="line"><span class="token" style="color: #032f62;">            s1.setOnClickListener();
</span></span><span class="line"><span class="token" style="color: #032f62;">            ~~~~~~~~~~~~~~~~~~~~~~~
</span></span><span class="line"><span class="token" style="color: #032f62;">    0 errors, 1 warnings
</span></span><span class="line"><span class="token" style="color: #032f62;">&quot;&quot;&quot;</span><span class="token">.trimIndent</span><span class="token">()
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6f42c1;">@Test</span><span class="token">
</span></span><span class="line"><span class="token">fun incorrectMethodUsage_shouldShowCorrectWarningMessage</span><span class="token">() {
</span></span><span class="line"><span class="token">    </span><span class="token">lint</span><span class="token">()
</span></span><span class="line"><span class="token">        </span><span class="token">.files</span><span class="token">(</span><span class="token">java</span><span class="token">(incorrectMethodCallJava))
</span></span><span class="line"><span class="token">        </span><span class="token">.run</span><span class="token">()
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">/*</span><span class="token" style="color: #6a737d;"> this check is sensitive to indentation so you might have to adjust warning variable a bit due to article formatting </span><span class="token" style="color: #6a737d;">*/</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">.expect</span><span class="token">(incorrectMethodCallWarning)
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-169"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-167">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-168'
	>
	And, of course, you want to check that your check won’t report any issues.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-171"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6f42c1;">@Test</span><span class="token">
</span></span><span class="line"><span class="token">fun correctMethodUsage_shouldNotShowAnyWarningMessages</span><span class="token">() {
</span></span><span class="line"><span class="token">    </span><span class="token">lint</span><span class="token">()
</span></span><span class="line"><span class="token">        </span><span class="token">.files</span><span class="token">(</span><span class="token">java</span><span class="token">(correctMethodCallJava))
</span></span><span class="line"><span class="token">        </span><span class="token">.run</span><span class="token">()
</span></span><span class="line"><span class="token">        </span><span class="token">.expectClean</span><span class="token">()
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-174"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-172">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-173'
	>
	A good starting point</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-177"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-175">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-176'
	>
	There are many more assertions that enable you to verify the correctness of your check (you can even check whole reports). </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-180"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-178">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-179'
	>
	The checks in this article can cover a lot of cases which are a good starting point for every type of a check that exists. For those eager to learn more, <a href="https://gist.github.com/mister11/a9c04e35bb3083416cf9651d91f463c4">here</a> you can find tests for XML checks. That’s all folks. Happy testing.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/how-to-test-custom-lint-checks/">How to Test Custom Lint Checks</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>7956https://infinum.com/uploads/2019/04/what-is-android-lint-and-how-helps-write-maintainable-code-0.webp</url>
				</image>
				<title>What Is Android Lint and How It Helps Write Maintainable Code</title>
				<link>https://infinum.com/blog/what-is-android-lint-and-how-helps-write-maintainable-code/</link>
				<pubDate>Thu, 04 Apr 2019 13:00:00 +0000</pubDate>
				<dc:creator>Sven Vidak</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/what-is-android-lint-and-how-helps-write-maintainable-code/</guid>
				<description>
					<![CDATA[<p>Classic developer oversights: using an API added in the newer version, actions requiring specific permissions, missing translations, etc.</p>
<p>The post <a href="https://infinum.com/blog/what-is-android-lint-and-how-helps-write-maintainable-code/">What Is Android Lint and How It Helps Write Maintainable Code</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-293"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-183">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-186"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-184">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-185'
	>
	When developers are not careful enough, things can go south. Classic developer oversights include the usage of an API added in the newer version that is not supported in the old versions, actions that require specific permissions, missing translations, just to name a few.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-189"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-187">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-188'
	>
	On top of that, Java, Kotlin, as well as any other programming languages have their own set of programming constructs that might result in poor performance.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-192"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-190">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-191'
	>
	Hello, Lint</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-195"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-193">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-194'
	>
	We use a tool called Lint (or Linter) to prevent such issues. Lint is a tool for static code analysis that helps developers catch potential issues before the code even compiles. It runs multiple checks on the source code that can detect issues like unused variables or function arguments, condition simplification, wrong scopes, undefined variables or functions, poorly optimized code, etc. When we talk about Android development, there are <a href="https://android.googlesource.com/platform/tools/base/+/master/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks">hundreds of existing Lint checks</a> available out-of-the-box.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-198"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-196">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-197'
	>
	But sometimes, we need to detect specific issues in our codebase that are not covered by those existing checks.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-201"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-199">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-200'
	>
	Hello, custom Lint check</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-204"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-202">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-203'
	>
	Before we start coding, let’s define our goal and see how to implement each part of that goal in terms of a Lint API. The goal is to create a check to detect the wrong method call on an object. The idea of this check is to detect if the method for setting click listener on an Android View component is the one that will throttle multiple consecutive clicks so we can avoid opening the same activity, or calling an API multiple times.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-207"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-205">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-206'
	>
	Custom Lint checks are written as a part of the standard Java (or Kotlin) module. The easiest way to start is to create a simple Gradle-based project (it doesn’t have to be an Android project).</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-210"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-208">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-209'
	>
	Next, you’d want to add Lint dependencies. In your module’s <code>build.gradle</code> file add:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-212"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-groovy github-light" data-language="groovy" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">compileOnly </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">com.android.tools.lint:lint-api:</span><span class="token" style="color: #24292e;">$l</span><span class="token" style="color: #24292e;">i</span><span class="token" style="color: #24292e;">n</span><span class="token" style="color: #24292e;">t</span><span class="token" style="color: #24292e;">V</span><span class="token" style="color: #24292e;">e</span><span class="token" style="color: #24292e;">r</span><span class="token" style="color: #24292e;">s</span><span class="token" style="color: #24292e;">i</span><span class="token" style="color: #24292e;">o</span><span class="token" style="color: #24292e;">n</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">compileOnly </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">com.android.tools.lint:lint-checks:</span><span class="token" style="color: #24292e;">$l</span><span class="token" style="color: #24292e;">i</span><span class="token" style="color: #24292e;">n</span><span class="token" style="color: #24292e;">t</span><span class="token" style="color: #24292e;">V</span><span class="token" style="color: #24292e;">e</span><span class="token" style="color: #24292e;">r</span><span class="token" style="color: #24292e;">s</span><span class="token" style="color: #24292e;">i</span><span class="token" style="color: #24292e;">o</span><span class="token" style="color: #24292e;">n</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-215"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-213">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-214'
	>
	Now, there’s a trick I’ve learned by researching this topic. <code>lintVersion</code> should be <code>gradlePluginVersion + 23.0.0</code>. <code>gradlePluginVersion</code> is a variable defined in root <code>build.gradle</code> project when you create an Android project using Android Studio and at this moment, the latest stable version is 3.3.0. That means that <code>lintVersion</code> should be 26.3.0.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-218"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-216">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-217'
	>
	Each Lint check consists of 4 parts:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-221"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-219">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-220'
	>
	<li><strong>Issue</strong> – the problem in our code we are trying to prevent from happening. When Lint check fails, this is what is reported to the user</li><li><strong>Detector</strong> – a tool for finding a problem that exposes parts of the source code to us in terms of a Lint API classes</li><li><strong>Implementation</strong> – scope in which a problem might happen (source file, XML file, compiled code, …)</li><li><strong>Registry</strong> – custom Lint check registry, which will be used alongside the existing registry that contains predefined checks</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-224"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-222">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-223'
	>
	Implementation</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-227"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-225">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-226'
	>
	Let’s start by creating an implementation for our custom check. Each implementation consists of a class that implements a detector and a scope.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-229"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">val </span><span class="token">correctClickListenerImplementation </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">Implementation</span><span class="token">(CorrectClickListenerDetector</span><span class="token">::</span><span class="token" style="color: #6f42c1;">class</span><span class="token">.java, Scope.JAVA_FILE_SCOPE)
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-232"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-230">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-231'
	>
	Have in mind that <code>Scope.JAVA_FILE_SCOPE</code> will also work for Kotlin classes.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-235"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-233">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-234'
	>
	Issue</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-238"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-236">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-237'
	>
	The next step is to use this implementation for defining an issue. Each issue consists of several parts:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-241"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-239">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-240'
	>
	<li><strong>ID</strong> – unique identifier</li><li><strong>Description</strong> – short (5-6 words) summary of an issue</li><li><strong>Explanation</strong> – full issue explanation with a suggestion on how to fix it</li><li><strong>Category</strong> – category of an issue (performance, translation, security, etc.)</li><li>Priority – the importance of the issue, in a range from 1 to 10 with 10 being the highest. This will be used to sort issues in a report generated by running Lint task</li><li>Severity – a severity of an issue (fatal, error, warning, info, or ignore)</li><li><strong>Implementation</strong> – implementation that will be used to detect this issue</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-243"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">val </span><span class="token">ISSUE_CLICK_LISTENER </span><span class="token" style="color: #d73a49;">=</span><span class="token"> Issue</span><span class="token">.create</span><span class="token">(
</span></span><span class="line"><span class="token">    id </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">UnsafeClickListener</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">,
</span></span><span class="line"><span class="token">    briefDescription </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Unsafe click listener</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">, 
</span></span><span class="line"><span class="token">    explanation </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;&quot;&quot;</span><span class="token" style="color: #032f62;">&quot;
</span></span><span class="line"><span class="token" style="color: #032f62;">        This check ensures you call click listener that is throttled 
</span></span><span class="line"><span class="token" style="color: #032f62;">        instead of a normal one which does not prevent double clicks.
</span></span><span class="line"><span class="token" style="color: #032f62;">        </span><span class="token" style="color: #032f62;">&quot;&quot;&quot;</span><span class="token">.trimIndent</span><span class="token">(),
</span></span><span class="line"><span class="token">    category </span><span class="token" style="color: #d73a49;">=</span><span class="token"> Category.CORRECTNESS,
</span></span><span class="line"><span class="token">    priority </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">6</span><span class="token">,
</span></span><span class="line"><span class="token">    severity </span><span class="token" style="color: #d73a49;">=</span><span class="token"> Severity.WARNING,
</span></span><span class="line"><span class="token">    implementation </span><span class="token" style="color: #d73a49;">=</span><span class="token"> correctClickListenerImplementation
</span></span><span class="line"><span class="token">)
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-246"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-244">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-245'
	>
	Detector</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-249"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-247">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-248'
	>
	Lint API offers interfaces for each scope you can define in the implementation. Each of these interfaces exposes methods that you can override and access parts of the code you are interested in.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-252"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-250">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-251'
	>
	<li><strong>UastScanner</strong> – Java or Kotlin files (UAST – <a href="https://www.techopedia.com/definition/22431/abstract-syntax-tree-ast">Unified Abstract Syntax Tree</a>)</li><li><strong>ClassScanner</strong> – compiled files (bytecode)</li><li><strong>BinaryResourceScanner</strong> – binary resources like bitmaps or <code>res/raw</code> files</li><li><strong>ResourceFolderScanner</strong> – resources folders (not specific files in them)</li><li><strong>XmlScanner</strong> – XML files</li><li><strong>GradleScanner</strong> – Gradle files</li><li><strong>OtherFileScanner</strong> – everything else</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-255"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-253">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-254'
	>
	Also, <code>Detector</code> class is a base class that has dummy implementations of all the methods each of the above interfaces exposes so you are not forced to implement a complete interface in case you need only one method.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-258"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-256">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-257'
	>
	Now, we are ready to implement a detector that will check the correct method call on an object.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-260"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token" style="color: #d73a49;">const</span><span class="token"> </span><span class="token">val </span><span class="token">REPORT_MESSAGE </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Use setThrottlingClickListener</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">/**</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #6a737d;"> * Custom detector class that extends base Detector class and specific
</span></span><span class="line"><span class="token" style="color: #6a737d;"> * interface depending on which part of the code we want to analyze.
</span></span><span class="line"><span class="token" style="color: #6a737d;"> </span><span class="token" style="color: #6a737d;">*/</span><span class="token">
</span></span><span class="line"><span class="token">class CorrectClickListenerDetector </span><span class="token">: </span><span class="token" style="color: #6f42c1;">Detector</span><span class="token">(), Detector</span><span class="token">.UastScanner </span><span class="token">{
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">/**</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #6a737d;">* Method that defines which elements of the code we want to analyze.
</span></span><span class="line"><span class="token" style="color: #6a737d;">* There are many similar methods for different elements in the code,
</span></span><span class="line"><span class="token" style="color: #6a737d;">* but for our use-case, we want to analyze method calls so we return
</span></span><span class="line"><span class="token" style="color: #6a737d;">* just one element representing method calls.
</span></span><span class="line"><span class="token" style="color: #6a737d;">*/</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">fun getApplicableUastTypes</span><span class="token">()</span><span class="token">: </span><span class="token" style="color: #6f42c1;">List</span><span class="token">&lt;</span><span class="token" style="color: #6f42c1;">Class</span><span class="token">&lt;</span><span class="token" style="color: #6f42c1;">out</span><span class="token"> </span><span class="token" style="color: #6f42c1;">UElement</span><span class="token">&gt;&gt;? </span><span class="token">{
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token">listOf</span><span class="token">&lt;</span><span class="token" style="color: #6f42c1;">Class</span><span class="token">&lt;</span><span class="token" style="color: #6f42c1;">out</span><span class="token"> </span><span class="token" style="color: #6f42c1;">UElement</span><span class="token">&gt;&gt;</span><span class="token">(UCallExpression</span><span class="token">::</span><span class="token" style="color: #6f42c1;">class</span><span class="token">.java)
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6a737d;">/**</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #6a737d;">    * Since we&amp;#8217;ve defined applicable UAST types, we have to override the
</span></span><span class="line"><span class="token" style="color: #6a737d;">    * method that will create UAST handler for those types.
</span></span><span class="line"><span class="token" style="color: #6a737d;">    * Handler requires implementation of an UElementHandler which is a
</span></span><span class="line"><span class="token" style="color: #6a737d;">    * class that defines a number of different methods that handle
</span></span><span class="line"><span class="token" style="color: #6a737d;">    * element like annotations, breaks, loops, imports, etc. In our case,
</span></span><span class="line"><span class="token" style="color: #6a737d;">    * we&amp;#8217;ve defined only call expressions so we override just this one method.
</span></span><span class="line"><span class="token" style="color: #6a737d;">    * Method implementation is pretty straight-forward - it checks if a method
</span></span><span class="line"><span class="token" style="color: #6a737d;">    * that is called has the name we want to avoid and it reports an issue otherwise.
</span></span><span class="line"><span class="token" style="color: #6a737d;">    </span><span class="token" style="color: #6a737d;">*/</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">fun createUastHandler</span><span class="token">(context</span><span class="token">: </span><span class="token" style="color: #6f42c1;">JavaContext</span><span class="token">)</span><span class="token">: </span><span class="token" style="color: #6f42c1;">UElementHandler</span><span class="token">? </span><span class="token">{
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #d73a49;">object</span><span class="token">: </span><span class="token" style="color: #6f42c1;">UElementHandler</span><span class="token">() {
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">fun visitCallExpression</span><span class="token">(node</span><span class="token">: </span><span class="token" style="color: #6f42c1;">UCallExpression</span><span class="token">) {
</span></span><span class="line"><span class="token">                </span><span class="token" style="color: #d73a49;">if</span><span class="token"> (node.methodName </span><span class="token" style="color: #d73a49;">!=</span><span class="token"> </span><span class="token" style="color: #005cc5;">null</span><span class="token"> </span><span class="token" style="color: #d73a49;">&amp;&amp;</span><span class="token"> node.methodName</span><span class="token">?.equals</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">setOnClickListener</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">, ignoreCase </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token">) </span><span class="token" style="color: #d73a49;">==</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token">) {
</span></span><span class="line"><span class="token">                    context</span><span class="token">.report</span><span class="token">(ISSUE_CLICK_LISTENER, node, context</span><span class="token">.getLocation</span><span class="token">(node), REPORT_MESSAGE, </span><span class="token">createFix</span><span class="token">())
</span></span><span class="line"><span class="token">                }
</span></span><span class="line"><span class="token">            }
</span></span><span class="line"><span class="token">        }
</span></span><span class="line"><span class="token">    }
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6a737d;">/**</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #6a737d;">     * Method will create a fix which can be trigger within IDE and
</span></span><span class="line"><span class="token" style="color: #6a737d;">     * it will replace incorrect method with a correct one.
</span></span><span class="line"><span class="token" style="color: #6a737d;">     </span><span class="token" style="color: #6a737d;">*/</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">private</span><span class="token"> </span><span class="token">fun createFix</span><span class="token">()</span><span class="token">: </span><span class="token" style="color: #6f42c1;">LintFix</span><span class="token"> </span><span class="token">{
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token">fix</span><span class="token">()</span><span class="token">.replace</span><span class="token">()</span><span class="token">.text</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">setOnClickListener</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">.with</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">setThrottlingClickListener</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">.build</span><span class="token">()
</span></span><span class="line"><span class="token">    }
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-263"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-261">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-262'
	>
	The last thing we need to do is add issues to our registry and tell Lint there is a custom registry of issues that it should use alongside a default one.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-265"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">class MyIssueRegistry </span><span class="token">: </span><span class="token" style="color: #6f42c1;">IssueRegistry</span><span class="token">() {
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">override</span><span class="token"> </span><span class="token">val </span><span class="token">issues</span><span class="token">: </span><span class="token" style="color: #6f42c1;">List</span><span class="token">&lt;</span><span class="token" style="color: #6f42c1;">Issue</span><span class="token">&gt; </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">listOf</span><span class="token">(ISSUE_CLICK_LISTENER)
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-268"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-266">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-267'
	>
	In module’s <code>build.gradle</code>:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-270"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-kotlin github-light" data-language="kotlin" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">jar </span><span class="token">{
</span></span><span class="line"><span class="token">    </span><span class="token">manifest </span><span class="token">{
</span></span><span class="line"><span class="token">        </span><span class="token">attributes</span><span class="token">(</span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">Lint-Registry-v2</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">: </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">co.infinum.lint.MyIssueRegistry</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)
</span></span><span class="line"><span class="token">    }
</span></span><span class="line"><span class="token">}
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-273"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-271">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-272'
	>
	where <code>co.infinum.lint</code> is package of <code>MyIssueRegistry</code> class. Now, you can run <code>jar</code> task using <code>gradlew</code> script and library should appear in <code>build/libs</code> directory.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-276"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-274">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-275'
	>
	There is another example of a custom Lint check <a href="https://gist.github.com/mister11/7ff029daae811859f4003814eb19e6ec">here</a> where you can see how to process XML files. The general idea is the same for this as for any other check – extend, specify and override functionality you need for the parts of the code that should be analyzed.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-279"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-277">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-278'
	>
	Usage</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-282"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-280">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-281'
	>
	Your brand new Lint check is ready to be used on a project. If this check can be applied to all projects, you can put it in <code>~/.android/lint</code> folder (you can create it if it doesn’t exist).</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-285"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-283">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-284'
	>
	Also, you can develop your check as a module in your project and include that module as any other dependency using the<code>lintChecks</code> method. This can also be used if you upload the<code>jar</code> file to Bintray.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-288"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-286">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-287'
	>
	Is it worth the trouble?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-291"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-289">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-290'
	>
	Lint is a really nice tool every developer should use. The ability to detect potential issues with your code upfront comes in handy. While custom checks are not the easiest to write, mostly due to the complexity of the API, they’re definitely worth it and can save a lot of time and effort down the road.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/what-is-android-lint-and-how-helps-write-maintainable-code/">What Is Android Lint and How It Helps Write Maintainable Code</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
		
	</channel>
</rss>