From 034e88f85a545209e40fb3535eb6780700d9f6c9 Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Thu, 5 Aug 2010 12:48:18 +0400 Subject: [PATCH] caching for groovy categories --- .../resources/standardDsls/metaDsl.gdsl | 4 +- .../groovy/dsl/CustomMembersGenerator.java | 6 ++ .../groovy/dsl/GdslMembersHolderConsumer.java | 3 + .../dsl/toplevel/CategoryMethodProvider.java | 72 +++++++++++++++++++ .../toplevel/GdslMetaClassProperties.groovy | 43 +---------- .../plugins/groovy/dsl/GroovyDslTest.groovy | 14 ++++ .../dsl/CategoryWhenMethodRenamed.groovy | 2 + .../CategoryWhenMethodRenamed_after.groovy | 2 + 8 files changed, 103 insertions(+), 43 deletions(-) create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/toplevel/CategoryMethodProvider.java create mode 100644 plugins/groovy/testdata/groovy/dsl/CategoryWhenMethodRenamed.groovy create mode 100644 plugins/groovy/testdata/groovy/dsl/CategoryWhenMethodRenamed_after.groovy diff --git a/plugins/groovy/resources/standardDsls/metaDsl.gdsl b/plugins/groovy/resources/standardDsls/metaDsl.gdsl index 796d1bf178d6..eeb0a67e64c8 100644 --- a/plugins/groovy/resources/standardDsls/metaDsl.gdsl +++ b/plugins/groovy/resources/standardDsls/metaDsl.gdsl @@ -22,8 +22,8 @@ contributor([gdslScriptContext]) { method name: "contributor", params: [contexts: "java.util.Map", body: {}], type: void method name: "contributor", params: [contexts: "java.lang.Object", body: {}], type: void - method name: "category", params: [categoryClass: "java.lang.String", isStatic:"java.lang.Boolean", body: {}], type: void - method name: "category", params: [categoryClass: "java.lang.String", body: {}], type: void + method name: "category", params: [categoryClass: "java.lang.String", isStatic:"java.lang.Boolean"], type: void + method name: "category", params: [categoryClass: "java.lang.String"], type: void method name: "supportsVersion", params: [version: "java.lang.String"], type: boolean diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/CustomMembersGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/CustomMembersGenerator.java index 362e8c7370b7..0853ae4e9eba 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/CustomMembersGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/CustomMembersGenerator.java @@ -2,6 +2,7 @@ package org.jetbrains.plugins.groovy.dsl; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; import groovy.lang.Closure; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.dsl.holders.CompoundMembersHolder; @@ -60,6 +61,11 @@ public class CustomMembersGenerator implements GdslMembersHolderConsumer { return JavaPsiFacade.getInstance(myProject).findClass(myQualifiedName, myDescriptor.getResolveScope()); } + @Override + public GlobalSearchScope getResolveScope() { + return myDescriptor.getResolveScope(); + } + public Project getProject() { return myProject; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GdslMembersHolderConsumer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GdslMembersHolderConsumer.java index e96b7244095f..5894e4c33e3e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GdslMembersHolderConsumer.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GdslMembersHolderConsumer.java @@ -20,6 +20,7 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; +import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.dsl.holders.CustomMembersHolder; @@ -34,4 +35,6 @@ public interface GdslMembersHolderConsumer { PsiType getPsiType(); @Nullable PsiClass getPsiClass(); + + GlobalSearchScope getResolveScope(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/toplevel/CategoryMethodProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/toplevel/CategoryMethodProvider.java new file mode 100644 index 000000000000..8efd1fe470db --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/toplevel/CategoryMethodProvider.java @@ -0,0 +1,72 @@ +/* + * Copyright 2000-2010 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.plugins.groovy.dsl.toplevel; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.util.Key; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.*; +import com.intellij.util.Function; +import com.intellij.util.containers.MultiMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +/** + * @author Maxim.Medvedev + */ +public class CategoryMethodProvider { + private static final Key>> METHOD_KEY = Key.create("Category methods"); + + private CategoryMethodProvider() { + } + + public static List provideMethods(@NotNull PsiType psiType, + final Project project, + String className, + GlobalSearchScope scope, + final Function converter) { + final PsiClass categoryClass = JavaPsiFacade.getInstance(project).findClass(className, scope); + if (categoryClass == null) return Collections.emptyList(); + final MultiMap map = CachedValuesManager.getManager(project) + .getCachedValue(categoryClass, METHOD_KEY, new CachedValueProvider>() { + @Override + public Result> compute() { + MultiMap map = new MultiMap(); + for (PsiMethod m : categoryClass.getMethods()) { + final PsiParameter[] params = m.getParameterList().getParameters(); + if (params.length == 0) continue; + final PsiType parameterType = params[0].getType(); + PsiType targetType = TypeConversionUtil.erasure(parameterType); + map.putValue(targetType.getCanonicalText(), converter.fun(m)); + } + return Result.create(map, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT, ProjectRootManager.getInstance(project)); + } + }, false); + Set superTypes = ResolveUtil.getAllSuperTypes(psiType, project).keySet(); + List result = new ArrayList(); + for (String superType : superTypes) { + result.addAll(map.get(superType)); + } + return result; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/toplevel/GdslMetaClassProperties.groovy b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/toplevel/GdslMetaClassProperties.groovy index 168563eb2fd0..4c4a913054b0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/toplevel/GdslMetaClassProperties.groovy +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/toplevel/GdslMetaClassProperties.groovy @@ -7,17 +7,7 @@ import org.jetbrains.plugins.groovy.dsl.toplevel.scopes.AnnotatedScope import org.jetbrains.plugins.groovy.dsl.toplevel.scopes.ClassScope import org.jetbrains.plugins.groovy.dsl.toplevel.scopes.ClosureScope import org.jetbrains.plugins.groovy.dsl.toplevel.scopes.ScriptScope -import com.intellij.psi.util.TypeConversionUtil -import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil -import com.intellij.psi.util.CachedValuesManager -import com.intellij.openapi.util.Key -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod -import com.intellij.psi.util.CachedValue -import com.intellij.psi.util.CachedValueProvider -import com.intellij.psi.util.CachedValueProvider.Result import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrGdkMethodImpl -import com.intellij.psi.util.PsiModificationTracker -import com.intellij.openapi.roots.ProjectRootManager import com.intellij.psi.PsiMethod import com.intellij.util.Function @@ -73,41 +63,12 @@ class GdslMetaClassProperties { private def processCategoryMethods (def className, Function converter) { contributor(context()) { if (!psiType) return; - - def categoryClass = findClass(className) - if (!categoryClass) return; - categoryClass.methods.each {m -> - def params = m.parameterList.parameters - if (!params) return; - def targetType = TypeConversionUtil.erasure(params[0].type) - if (!ResolveUtil.isInheritor(psiType, targetType.getCanonicalText(), project)) return; - - add CachedValuesManager.getManager(project). - getCachedValue(m, CategoryMethodProvider.CATEGORY_METHOD, new CategoryMethodProvider(m, converter), false) - } + List methods = CategoryMethodProvider.provideMethods(psiType, project, className, resolveScope, converter) + for (m in methods) add m } } - static class CategoryMethodProvider implements CachedValueProvider { - static final Key> CATEGORY_METHOD = Key.create("category method"); - - def method - def converter - - def CategoryMethodProvider(def method, def converter) { - this.method = method; - this.converter = converter - } - - Result compute() { - return Result.create( - converter.fun(method), - PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT, - ProjectRootManager.getInstance(method.project)); - } - } - /** * Auxiliary methods for context definition */ diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/dsl/GroovyDslTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/dsl/GroovyDslTest.groovy index cdcabd3c709a..e57c7f4a2956 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/dsl/GroovyDslTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/dsl/GroovyDslTest.groovy @@ -25,6 +25,7 @@ import com.intellij.testFramework.PsiTestUtil import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase import org.jetbrains.plugins.groovy.util.TestUtils +import com.intellij.psi.PsiClass /** * @author peter @@ -123,4 +124,17 @@ public class GroovyDslTest extends LightCodeInsightFixtureTestCase { return descriptor; } + public void testCategoryWhenMethodRenamed() { + PsiClass category = myFixture.addClass(""" +public class MyCategory { + public void foo(String s) {} +}""") + def foo = category.getMethods()[0] + final PsiFile file = myFixture.addFileToProject(getTestName(false) + "Enhancer.gdsl", """ +category 'MyCategory'"""); + GroovyDslFileIndex.activateUntilModification(file.virtualFile) + myFixture.renameElement foo, "bar", false, false + + myFixture.testCompletion(getTestName(false) + ".groovy", getTestName(false) + "_after.groovy") + } } diff --git a/plugins/groovy/testdata/groovy/dsl/CategoryWhenMethodRenamed.groovy b/plugins/groovy/testdata/groovy/dsl/CategoryWhenMethodRenamed.groovy new file mode 100644 index 000000000000..2d2365d834e1 --- /dev/null +++ b/plugins/groovy/testdata/groovy/dsl/CategoryWhenMethodRenamed.groovy @@ -0,0 +1,2 @@ +def s = "foo" +s.ba \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/dsl/CategoryWhenMethodRenamed_after.groovy b/plugins/groovy/testdata/groovy/dsl/CategoryWhenMethodRenamed_after.groovy new file mode 100644 index 000000000000..c6a76d20ee76 --- /dev/null +++ b/plugins/groovy/testdata/groovy/dsl/CategoryWhenMethodRenamed_after.groovy @@ -0,0 +1,2 @@ +def s = "foo" +s.bar() \ No newline at end of file