From d1939d52bca098d4e39855f6c36f6d70e66a7fe7 Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Thu, 10 Mar 2016 16:25:18 +0300 Subject: [PATCH] Replace UastConverter with UastLanguagePlugin, allow additional checkers --- .../client/api/JavaLintLanguageExtension.java | 15 ++++++-- .../tools/klint/client/api/LintClient.java | 4 +-- .../tools/klint/client/api/LintDriver.java | 19 +++++------ .../client/api/LintLanguageExtension.java | 18 ++++------ .../tools/klint/detector/api/JavaContext.java | 4 +-- .../tools/klint/detector/api/Scope.java | 2 +- .../klint/checks/PermissionRequirement.java | 13 +++---- .../klint/AndroidLintExternalAnnotator.java | 2 +- .../inspections/klint/IntellijLintClient.java | 10 +++--- .../klint/KotlinLintLanguageExtension.kt | 5 +-- .../check/AndroidUastAdditionalChecker.kt} | 9 ++--- .../org/jetbrains/uast/check/UastChecker.kt | 34 +++++++++++++------ .../src/org/jetbrains/uast/UastContext.kt | 6 ++-- ...UastConverter.kt => UastLanguagePlugin.kt} | 13 +++++-- ...Converter.kt => JavaUastLanguagePlugin.kt} | 7 +++- ...nverter.kt => KotlinUastLanguagePlugin.kt} | 12 +++++-- 16 files changed, 105 insertions(+), 68 deletions(-) rename plugins/lint/{lint-idea/src/org/jetbrains/kotlin/lint/KotlinLintLanguageExtension.kt => uast-android/src/org/jetbrains/uast/check/AndroidUastAdditionalChecker.kt} (69%) rename plugins/uast-common/src/org/jetbrains/uast/{UastConverter.kt => UastLanguagePlugin.kt} (68%) rename plugins/uast-java/src/org/jetbrains/uast/java/{JavaConverter.kt => JavaUastLanguagePlugin.kt} (98%) rename plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/{KotlinConverter.kt => KotlinUastLanguagePlugin.kt} (94%) diff --git a/plugins/lint/lint-api/src/com/android/tools/klint/client/api/JavaLintLanguageExtension.java b/plugins/lint/lint-api/src/com/android/tools/klint/client/api/JavaLintLanguageExtension.java index 06ccbf6c619..d884ef1c398 100644 --- a/plugins/lint/lint-api/src/com/android/tools/klint/client/api/JavaLintLanguageExtension.java +++ b/plugins/lint/lint-api/src/com/android/tools/klint/client/api/JavaLintLanguageExtension.java @@ -16,12 +16,23 @@ package com.android.tools.klint.client.api; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.uast.UastAdditionalChecker; import org.jetbrains.uast.UastConverter; -import org.jetbrains.uast.java.JavaConverter; +import org.jetbrains.uast.java.JavaUastLanguagePlugin; + +import java.util.List; public class JavaLintLanguageExtension extends LintLanguageExtension { + @NotNull @Override public UastConverter getConverter() { - return JavaConverter.INSTANCE; + return JavaUastLanguagePlugin.INSTANCE.getConverter(); + } + + @NotNull + @Override + public List getAdditionalCheckers() { + return JavaUastLanguagePlugin.INSTANCE.getAdditionalCheckers(); } } diff --git a/plugins/lint/lint-api/src/com/android/tools/klint/client/api/LintClient.java b/plugins/lint/lint-api/src/com/android/tools/klint/client/api/LintClient.java index d34c89a6f51..75eeee87656 100755 --- a/plugins/lint/lint-api/src/com/android/tools/klint/client/api/LintClient.java +++ b/plugins/lint/lint-api/src/com/android/tools/klint/client/api/LintClient.java @@ -40,7 +40,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.io.Files; -import org.jetbrains.uast.UastConverter; +import org.jetbrains.uast.UastLanguagePlugin; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -386,7 +386,7 @@ public abstract class LintClient { return null; } - public List getConverters() { + public List getLanguagePlugins() { return Collections.emptyList(); } diff --git a/plugins/lint/lint-api/src/com/android/tools/klint/client/api/LintDriver.java b/plugins/lint/lint-api/src/com/android/tools/klint/client/api/LintDriver.java index cdc9c00b15b..83edd30eae9 100644 --- a/plugins/lint/lint-api/src/com/android/tools/klint/client/api/LintDriver.java +++ b/plugins/lint/lint-api/src/com/android/tools/klint/client/api/LintDriver.java @@ -1445,7 +1445,7 @@ public class LintDriver { if (ideaProject == null) { return; } - List converters = mClient.getConverters(); + List plugins = mClient.getLanguagePlugins(); for (JavaContext context : contexts) { fireEvent(LintListener.EventType.SCANNING_FILE, context); @@ -1456,10 +1456,10 @@ public class LintDriver { UastVisitor customVisitor = scanner.createUastVisitor(context); if (customVisitor != null) { UastChecker.INSTANCE.checkWithCustomHandler( - ideaProject, context.file, converters, customVisitor); + ideaProject, context.file, plugins, customVisitor); } else { UastChecker.INSTANCE.check( - ideaProject, context.file, (UastScanner)check, converters, context); + ideaProject, context.file, (UastScanner)check, plugins, context); } } } @@ -1498,7 +1498,7 @@ public class LintDriver { } UastChecker checker = UastChecker.INSTANCE; - List converters = project.getClient().getConverters(); + List plugins = project.getClient().getLanguagePlugins(); for (File file : files) { if (!file.isFile()) { @@ -1506,7 +1506,7 @@ public class LintDriver { } String path = file.getPath(); - if (!path.endsWith(DOT_JAVA) && !UastConverterUtils.isFileSupported(converters, path)) { + if (!path.endsWith(DOT_JAVA) && !UastConverterUtils.isFileSupported(plugins, path)) { continue; } @@ -1516,9 +1516,9 @@ public class LintDriver { for (UastScanner detector : detectors) { UastVisitor customHandler = detector.createUastVisitor(context); if (customHandler != null) { - checker.checkWithCustomHandler(intellijProject, file, converters, customHandler); + checker.checkWithCustomHandler(intellijProject, file, plugins, customHandler); } else { - checker.check(intellijProject, file, detector, converters, context); + checker.check(intellijProject, file, detector, plugins, context); } } } @@ -2043,9 +2043,8 @@ public class LintDriver { } @Override - public List getConverters() { - return mDelegate.getConverters(); - + public List getLanguagePlugins() { + return mDelegate.getLanguagePlugins(); } } diff --git a/plugins/lint/lint-api/src/com/android/tools/klint/client/api/LintLanguageExtension.java b/plugins/lint/lint-api/src/com/android/tools/klint/client/api/LintLanguageExtension.java index e6245026482..be8f888751b 100644 --- a/plugins/lint/lint-api/src/com/android/tools/klint/client/api/LintLanguageExtension.java +++ b/plugins/lint/lint-api/src/com/android/tools/klint/client/api/LintLanguageExtension.java @@ -16,22 +16,18 @@ package com.android.tools.klint.client.api; -import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.project.Project; -import org.jetbrains.uast.UastConverter; +import org.jetbrains.uast.UastLanguagePlugin; import java.util.ArrayList; import java.util.Collections; import java.util.List; -public abstract class LintLanguageExtension { +public abstract class LintLanguageExtension implements UastLanguagePlugin { public static final ExtensionPointName EP_NAME = - ExtensionPointName.create("com.android.tools.lint.client.api.lintLanguageExtension"); - - @NonNull - public abstract UastConverter getConverter(); + ExtensionPointName.create("com.android.tools.klint.client.api.lintLanguageExtension"); public static boolean isFileSupported(@Nullable Project project, String path) { LintLanguageExtension[] extensions = getExtensions(project); @@ -44,16 +40,14 @@ public abstract class LintLanguageExtension { return false; } - public static List getConverters(@Nullable Project project) { + public static List getPlugins(@Nullable Project project) { if (project == null) { return Collections.emptyList(); } LintLanguageExtension[] languageExtensions = project.getExtensions(EP_NAME); - List converters = new ArrayList(languageExtensions.length); - for (LintLanguageExtension extension : languageExtensions) { - converters.add(extension.getConverter()); - } + List converters = new ArrayList(languageExtensions.length); + Collections.addAll(converters, languageExtensions); return converters; } diff --git a/plugins/lint/lint-api/src/com/android/tools/klint/detector/api/JavaContext.java b/plugins/lint/lint-api/src/com/android/tools/klint/detector/api/JavaContext.java index f3796632fe3..982ebd9f986 100644 --- a/plugins/lint/lint-api/src/com/android/tools/klint/detector/api/JavaContext.java +++ b/plugins/lint/lint-api/src/com/android/tools/klint/detector/api/JavaContext.java @@ -155,8 +155,8 @@ public class JavaContext extends Context implements UastAndroidContext { @NotNull @Override - public List getConverters() { - return getClient().getConverters(); + public List getLanguagePlugins() { + return getClient().getLanguagePlugins(); } @org.jetbrains.annotations.Nullable diff --git a/plugins/lint/lint-api/src/com/android/tools/klint/detector/api/Scope.java b/plugins/lint/lint-api/src/com/android/tools/klint/detector/api/Scope.java index c2c0795f336..4928db54697 100644 --- a/plugins/lint/lint-api/src/com/android/tools/klint/detector/api/Scope.java +++ b/plugins/lint/lint-api/src/com/android/tools/klint/detector/api/Scope.java @@ -203,7 +203,7 @@ public enum Scope { scope.add(BINARY_RESOURCE_FILE); scope.add(RESOURCE_FOLDER); } else if (UastConverterUtils.isFileSupported( - project.getClient().getConverters(), name)) { + project.getClient().getLanguagePlugins(), name)) { scope.add(SOURCE_FILE); } } diff --git a/plugins/lint/lint-checks/src/com/android/tools/klint/checks/PermissionRequirement.java b/plugins/lint/lint-checks/src/com/android/tools/klint/checks/PermissionRequirement.java index 1025f2f5a27..0088e8776ea 100644 --- a/plugins/lint/lint-checks/src/com/android/tools/klint/checks/PermissionRequirement.java +++ b/plugins/lint/lint-checks/src/com/android/tools/klint/checks/PermissionRequirement.java @@ -39,7 +39,7 @@ import com.intellij.psi.PsiElementFactory; import org.jetbrains.annotations.NotNull; import org.jetbrains.uast.*; import org.jetbrains.uast.check.UastAndroidContext; -import org.jetbrains.uast.java.JavaConverter; +import org.jetbrains.uast.java.JavaUastLanguagePlugin; import org.jetbrains.uast.visitor.UastVisitor; /** @@ -581,11 +581,12 @@ public abstract class PermissionRequirement { PsiElementFactory factory = JavaPsiFacade.getInstance( context.getClient().getProject()).getElementFactory(); - UElement node = JavaConverter.INSTANCE.convertWithParent(factory.createClassFromText( - "class Test { void test() {\n" - + "boolean result = " + value - + ";\n}\n}" - , null).getContainingFile()); + UElement node = JavaUastLanguagePlugin.INSTANCE.getConverter(). + convertWithParent(factory.createClassFromText( + "class Test { void test() {\n" + + "boolean result = " + value + + ";\n}\n}" + , null).getContainingFile()); if (node != null) { final AtomicReference reference = new AtomicReference(); diff --git a/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/AndroidLintExternalAnnotator.java b/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/AndroidLintExternalAnnotator.java index 23b804a404f..63b0a1b3528 100644 --- a/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/AndroidLintExternalAnnotator.java +++ b/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/AndroidLintExternalAnnotator.java @@ -148,7 +148,7 @@ public class AndroidLintExternalAnnotator extends ExternalAnnotator myModuleMap; @NonNull - private List myConverters; + private List myPlugins; protected IntellijLintClient(@NonNull Project project) { myProject = project; - myConverters = LintLanguageExtension.getConverters(project); + myPlugins = LintLanguageExtension.getPlugins(project); } /** Creates a lint client for batch inspections */ @@ -393,8 +393,8 @@ public class IntellijLintClient extends com.android.tools.klint.client.api.LintC } @Override - public List getConverters() { - return myConverters; + public List getLanguagePlugins() { + return myPlugins; } // Overridden such that lint doesn't complain about missing a bin dir property in the event diff --git a/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/KotlinLintLanguageExtension.kt b/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/KotlinLintLanguageExtension.kt index bd0f61299bf..b95397efc03 100644 --- a/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/KotlinLintLanguageExtension.kt +++ b/plugins/lint/lint-idea/src/org/jetbrains/android/inspections/klint/KotlinLintLanguageExtension.kt @@ -17,8 +17,9 @@ package org.jetbrains.android.inspections.klint import com.android.tools.klint.client.api.LintLanguageExtension -import org.jetbrains.kotlin.uast.KotlinConverter +import org.jetbrains.kotlin.uast.KotlinUastLanguagePlugin class KotlinLintLanguageExtension : LintLanguageExtension() { - override fun getConverter() = KotlinConverter + override val converter = KotlinUastLanguagePlugin.converter + override val additionalCheckers = KotlinUastLanguagePlugin.additionalCheckers } \ No newline at end of file diff --git a/plugins/lint/lint-idea/src/org/jetbrains/kotlin/lint/KotlinLintLanguageExtension.kt b/plugins/lint/uast-android/src/org/jetbrains/uast/check/AndroidUastAdditionalChecker.kt similarity index 69% rename from plugins/lint/lint-idea/src/org/jetbrains/kotlin/lint/KotlinLintLanguageExtension.kt rename to plugins/lint/uast-android/src/org/jetbrains/uast/check/AndroidUastAdditionalChecker.kt index a72fcdebdaf..ca372b1a8f4 100644 --- a/plugins/lint/lint-idea/src/org/jetbrains/kotlin/lint/KotlinLintLanguageExtension.kt +++ b/plugins/lint/uast-android/src/org/jetbrains/uast/check/AndroidUastAdditionalChecker.kt @@ -14,11 +14,8 @@ * limitations under the License. */ -package org.jetbrains.kotlin.lint +package org.jetbrains.uast.check -import com.android.tools.klint.client.api.LintLanguageExtension -import org.jetbrains.kotlin.uast.KotlinConverter +import org.jetbrains.uast.UastAdditionalChecker -class KotlinLintLanguageExtension : LintLanguageExtension() { - override fun getConverter() = KotlinConverter -} \ No newline at end of file +interface AndroidUastAdditionalChecker : UastAdditionalChecker \ No newline at end of file diff --git a/plugins/lint/uast-android/src/org/jetbrains/uast/check/UastChecker.kt b/plugins/lint/uast-android/src/org/jetbrains/uast/check/UastChecker.kt index cba09ee03ea..bb93c7a1169 100644 --- a/plugins/lint/uast-android/src/org/jetbrains/uast/check/UastChecker.kt +++ b/plugins/lint/uast-android/src/org/jetbrains/uast/check/UastChecker.kt @@ -26,7 +26,7 @@ import com.intellij.psi.PsiManager import org.jetbrains.uast.* import org.jetbrains.uast.UastCallKind.Companion.CONSTRUCTOR_CALL import org.jetbrains.uast.UastCallKind.Companion.FUNCTION_CALL -import org.jetbrains.uast.java.JavaConverter +import org.jetbrains.uast.java.JavaUastLanguagePlugin import org.jetbrains.uast.visitor.UastVisitor import java.io.File @@ -41,12 +41,12 @@ object UastChecker { fun checkWithCustomHandler( project: Project, file: File, - converters: List, + converters: List, visitor: UastVisitor) { check(project, file, converters, UastHandler { visitor.handle(it) }) } - fun check(project: Project, file: File, converters: List, handler: UastHandler) { + fun check(project: Project, file: File, plugins: List, handler: UastHandler) { val vfile = VirtualFileManager.getInstance().findFileByUrl("file://" + file.absolutePath) ?: return ApplicationManager.getApplication().runReadAction { val psiFile = PsiManager.getInstance(project).findFile(vfile) @@ -54,11 +54,11 @@ object UastChecker { if (psiFile != null) { when (psiFile) { is PsiJavaFile -> { - val ufile = JavaConverter.convert(psiFile) - ufile.handleTraverse(handler) + val ufile = JavaUastLanguagePlugin.converter.convertWithParent(psiFile) + ufile?.handleTraverse(handler) } - else -> for (converter in converters) { - val ufile = converter.convertWithParent(psiFile) + else -> for (plugin in plugins) { + val ufile = plugin.converter.convertWithParent(psiFile) if (ufile != null) { ufile.handleTraverse(handler) break @@ -69,12 +69,20 @@ object UastChecker { } } - fun check(project: Project, file: File, scanner: UastScanner, converters: List, context: UastAndroidContext) { + fun check(project: Project, file: File, scanner: UastScanner, plugins: List, context: UastAndroidContext) { val applicableFunctionNames = scanner.applicableFunctionNames ?: emptyList() val applicableSuperClasses = scanner.applicableSuperClasses ?: emptyList() val applicableConstructorTypes = scanner.applicableConstructorTypes ?: emptyList() - check(project, file, converters, UastHandler { element -> + val additionalCheckers = plugins.fold(mutableListOf()) { list, plugin -> + for (checker in plugin.additionalCheckers) { + if (checker is AndroidUastAdditionalChecker) list += checker + } + list + } + + var handler: UastHandler? = null + handler = UastHandler { element -> when (element) { is UCallExpression -> { if (applicableFunctionNames.isNotEmpty()) { @@ -99,7 +107,13 @@ object UastChecker { } } } - }) + + for (checker in additionalCheckers) { + checker(element, handler!!, context) + } + } + + check(project, file, plugins, handler) } } \ No newline at end of file diff --git a/plugins/uast-common/src/org/jetbrains/uast/UastContext.kt b/plugins/uast-common/src/org/jetbrains/uast/UastContext.kt index 87624d88822..e84032d8af2 100644 --- a/plugins/uast-common/src/org/jetbrains/uast/UastContext.kt +++ b/plugins/uast-common/src/org/jetbrains/uast/UastContext.kt @@ -16,15 +16,15 @@ package org.jetbrains.uast interface UastContext { - val converters: List + val languagePlugins: List fun convert(element: Any?): UElement? { if (element == null) { return null } - for (converter in converters) { - val uelement = converter.convertWithParent(element) + for (plugin in languagePlugins) { + val uelement = plugin.converter.convertWithParent(element) if (uelement != null) { return uelement } diff --git a/plugins/uast-common/src/org/jetbrains/uast/UastConverter.kt b/plugins/uast-common/src/org/jetbrains/uast/UastLanguagePlugin.kt similarity index 68% rename from plugins/uast-common/src/org/jetbrains/uast/UastConverter.kt rename to plugins/uast-common/src/org/jetbrains/uast/UastLanguagePlugin.kt index 34a8248cc71..7ffab018c91 100644 --- a/plugins/uast-common/src/org/jetbrains/uast/UastConverter.kt +++ b/plugins/uast-common/src/org/jetbrains/uast/UastLanguagePlugin.kt @@ -22,9 +22,18 @@ interface UastConverter { fun isFileSupported(path: String): Boolean } +interface UastLanguagePlugin { + val converter: UastConverter + val additionalCheckers: List +} + +interface UastAdditionalChecker { + operator fun invoke(element: UElement, handler: UastHandler, context: UastContext) +} + object UastConverterUtils { @JvmStatic - fun isFileSupported(converters: List, path: String): Boolean { - return converters.any { it.isFileSupported(path) } + fun isFileSupported(converters: List, path: String): Boolean { + return converters.any { it.converter.isFileSupported(path) } } } \ No newline at end of file diff --git a/plugins/uast-java/src/org/jetbrains/uast/java/JavaConverter.kt b/plugins/uast-java/src/org/jetbrains/uast/java/JavaUastLanguagePlugin.kt similarity index 98% rename from plugins/uast-java/src/org/jetbrains/uast/java/JavaConverter.kt rename to plugins/uast-java/src/org/jetbrains/uast/java/JavaUastLanguagePlugin.kt index fb8c8319037..69f8de40ba2 100644 --- a/plugins/uast-java/src/org/jetbrains/uast/java/JavaConverter.kt +++ b/plugins/uast-java/src/org/jetbrains/uast/java/JavaUastLanguagePlugin.kt @@ -19,7 +19,12 @@ package org.jetbrains.uast.java import com.intellij.psi.* import org.jetbrains.uast.* -object JavaConverter : UastConverter { +object JavaUastLanguagePlugin : UastLanguagePlugin { + override val converter: UastConverter = JavaConverter + override val additionalCheckers = emptyList() +} + +internal object JavaConverter : UastConverter { override fun isFileSupported(path: String): Boolean { return path.endsWith(".java", ignoreCase = true) } diff --git a/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/KotlinConverter.kt b/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/KotlinUastLanguagePlugin.kt similarity index 94% rename from plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/KotlinConverter.kt rename to plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/KotlinUastLanguagePlugin.kt index c10f43ce042..60d9d784ef6 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/KotlinConverter.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/KotlinUastLanguagePlugin.kt @@ -25,9 +25,15 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.uast.lint.PropertyAsCallAndroidUastAdditionalChecker import org.jetbrains.uast.* -object KotlinConverter : UastConverter { +object KotlinUastLanguagePlugin : UastLanguagePlugin { + override val converter: UastConverter = KotlinConverter + override val additionalCheckers = listOf(PropertyAsCallAndroidUastAdditionalChecker()) +} + +internal object KotlinConverter : UastConverter { override fun isFileSupported(path: String) = path.endsWith(".kt", false) || path.endsWith(".kts", false) override fun convert(element: Any?, parent: UElement): UElement? { @@ -142,7 +148,7 @@ object KotlinConverter : UastConverter { is KtBlockExpression -> KotlinUBlockExpression(expression, parent) is KtConstantExpression -> KotlinULiteralExpression(expression, parent) is KtTryExpression -> KotlinUTryExpression(expression, parent) - is KtArrayAccessExpression -> KotlinUArrayAccess(expression, parent) + is KtArrayAccessExpression -> KotlinUArrayAccessExpression(expression, parent) is KtLambdaExpression -> KotlinULambdaExpression(expression, parent) is KtBinaryExpressionWithTypeRHS -> KotlinUBinaryExpressionWithType(expression, parent) @@ -166,7 +172,7 @@ object KotlinConverter : UastConverter { internal fun asSimpleReference(element: PsiElement?, parent: UElement): USimpleReferenceExpression? { if (element == null) return null - return KotlinUSimpleReferenceExpression(element, KtPsiUtil.unquoteIdentifier(element.text), parent) + return KotlinNameUSimpleReferenceExpression(element, KtPsiUtil.unquoteIdentifier(element.text), parent) } internal fun convertOrEmpty(expression: KtExpression?, parent: UElement): UExpression {