Skip to content

Commit

Permalink
Show calls of TODO() function in TODO view
Browse files Browse the repository at this point in the history
 #KT-8617 Fixed
  • Loading branch information
yole committed May 19, 2017
1 parent c8b0bd4 commit ded5bfb
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ class KotlinFilterLexer(private val occurrenceConsumer: OccurrenceConsumer): Bas
}
else {
addOccurrenceInToken(UsageSearchContext.IN_CODE.toInt())
if (myDelegate.tokenText == "TODO" ) {
// Heuristics to reduce mismatches between indexer and searcher. The searcher returns only occurrences of TO_DO
// as the callee of a call expression, but we can't tell calls and other usages apart based on limited lexer context,
// so we just exclude occurrences in declaration names (and even that doesn't work precisely because it doesn't handle
// declarations with type parameters)
val prevToken = prevTokens.peekFirst()
if (prevToken != KtTokens.FUN_KEYWORD && prevToken != KtTokens.VAR_KEYWORD && prevToken != KtTokens.VAL_KEYWORD && prevToken != KtTokens.CLASS_KEYWORD) {
advanceTodoItemCountsInToken()
}
}
}
}

Expand Down Expand Up @@ -125,5 +135,7 @@ class KotlinIdIndexer: LexerBasedIdIndexer() {
}

class KotlinTodoIndexer: LexerBasedTodoIndexer(), IdAndToDoScannerBasedOnFilterLexer {
override fun createLexer(consumer: OccurrenceConsumer): Lexer = KotlinFilterLexer(consumer)
override fun getVersion() = 2

override fun createLexer(consumer: OccurrenceConsumer) = KotlinFilterLexer(consumer)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,21 @@
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathMacros;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.updateSettings.impl.UpdateChecker;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.search.searches.IndexPatternSearch;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.caches.JarUserDataManager;
import org.jetbrains.kotlin.idea.debugger.filter.DebuggerFiltersUtilKt;
import org.jetbrains.kotlin.idea.framework.CommonLibraryDetectionUtil;
import org.jetbrains.kotlin.idea.framework.KotlinJavaScriptLibraryDetectionUtil;
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinTodoSearcher;
import org.jetbrains.kotlin.utils.PathUtil;

import java.io.File;
Expand Down Expand Up @@ -81,6 +84,8 @@ public void documentChanged(DocumentEvent e) {
}
}
});

ServiceManager.getService(IndexPatternSearch.class).registerExecutor(new KotlinTodoSearcher());
}

private static void registerPathVariable() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.jetbrains.kotlin.idea.search.ideaExtensions

import com.intellij.openapi.application.QueryExecutorBase
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiFile
import com.intellij.psi.impl.cache.TodoCacheManager
import com.intellij.psi.search.IndexPattern
import com.intellij.psi.search.IndexPatternOccurrence
import com.intellij.psi.search.searches.IndexPatternSearch
import com.intellij.util.Processor
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtTreeVisitorVoid

data class KotlinTodoOccurrence(private val _file: PsiFile, private val _textRange: TextRange, private val _pattern: IndexPattern) : IndexPatternOccurrence {
override fun getFile() = _file
override fun getPattern() = _pattern
override fun getTextRange() = _textRange
}

class KotlinTodoSearcher : QueryExecutorBase<IndexPatternOccurrence, IndexPatternSearch.SearchParameters>(true) {
override fun processQuery(queryParameters: IndexPatternSearch.SearchParameters, consumer: Processor<IndexPatternOccurrence>) {
var pattern = queryParameters.pattern
if (pattern != null && !pattern.patternString.contains("TODO", true)) return
if (pattern == null) {
pattern = queryParameters.patternProvider.indexPatterns.firstOrNull { it.patternString.contains("TODO", true) } ?: return
}

val file = queryParameters.file

val cacheManager = TodoCacheManager.SERVICE.getInstance(file.project)
val patternProvider = queryParameters.patternProvider
val count = if (patternProvider != null) {
cacheManager.getTodoCount(file.virtualFile, patternProvider)}
else
cacheManager.getTodoCount(file.virtualFile, pattern)
if (count == 0) return

file.accept(object : KtTreeVisitorVoid() {
override fun visitCallExpression(expression: KtCallExpression) {
if (expression.calleeExpression?.text == "TODO") {
val argList = expression.valueArgumentList
if (argList?.arguments?.size == 1) {
consumer.process(KotlinTodoOccurrence(file, expression.textRange, pattern))
}
}
}
})
}
}
1 change: 1 addition & 0 deletions idea/testData/search/todo/todoCall.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fun foo() = TODO("Fix me")
4 changes: 4 additions & 0 deletions idea/testData/search/todo/todoDecl.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fun TODO() {
}

val TODO = 1
43 changes: 43 additions & 0 deletions idea/tests/org/jetbrains/kotlin/search/TodoSearchTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.jetbrains.kotlin.search

import com.intellij.psi.search.PsiTodoSearchHelper
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import java.io.File

class TodoSearchTest : KotlinLightCodeInsightFixtureTestCase() {
override fun getProjectDescriptor(): KotlinLightProjectDescriptor = KotlinLightProjectDescriptor.INSTANCE

override fun getTestDataPath(): String {
return File(PluginTestCaseBase.getTestDataPathBase(), "/search/todo").path + File.separator
}

fun testTodoCall() {
val file = myFixture.configureByFile("todoCall.kt")
val todoItems = PsiTodoSearchHelper.SERVICE.getInstance(myFixture.project).findTodoItems(file)
assertEquals(1, todoItems.size)
assertEquals("TODO(\"Fix me\")", todoItems[0].textRange.substring(todoItems[0].file.text))
}

fun testTodoDef() {
val file = myFixture.configureByFile("todoDecl.kt")
assertEquals(0, PsiTodoSearchHelper.SERVICE.getInstance(myFixture.project).getTodoItemsCount(file))
}
}

0 comments on commit ded5bfb

Please sign in to comment.