From 014607606e44cdbff135d2a3d11f0346cfc3a98f Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Tue, 31 Oct 2017 15:59:53 +0300 Subject: [PATCH 01/43] [groovy] allow @Nullable name for static members processor In this case the name will be retrieved from underlying processor. --- .../StaticMembersFilteringProcessor.java | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/StaticMembersFilteringProcessor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/StaticMembersFilteringProcessor.java index 3678f38ab058..1263daf3dc95 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/StaticMembersFilteringProcessor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/StaticMembersFilteringProcessor.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.resolve.processors; import com.intellij.psi.PsiElement; @@ -21,10 +7,11 @@ import com.intellij.psi.PsiModifier; import com.intellij.psi.ResolveState; import com.intellij.psi.scope.PsiScopeProcessor; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class StaticMembersFilteringProcessor extends GrDelegatingScopeProcessorWithHints { - public StaticMembersFilteringProcessor(@NotNull PsiScopeProcessor delegate, @NotNull String name) { + public StaticMembersFilteringProcessor(@NotNull PsiScopeProcessor delegate, @Nullable String name) { super(delegate, name, null); } From e556510a9b06d8f76445f071ab5b256a5cb623fe Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Tue, 31 Oct 2017 16:05:13 +0300 Subject: [PATCH 02/43] [groovy] fix typo in `shouldProcessMethods()` --- .../lang/resolve/CategoryMemberContributor.kt | 18 ++---------------- .../plugins/groovy/lang/resolve/ResolveUtil.kt | 2 +- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/CategoryMemberContributor.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/CategoryMemberContributor.kt index e1eb50a2ab12..1ca35e481024 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/CategoryMemberContributor.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/CategoryMemberContributor.kt @@ -1,18 +1,4 @@ -/* - * Copyright 2000-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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.psi.* @@ -33,7 +19,7 @@ import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint class CategoryMemberContributor : NonCodeMembersContributor() { override fun processDynamicElements(qualifierType: PsiType, processor: PsiScopeProcessor, place: PsiElement, state: ResolveState) { - if (!processor.shoudProcessMethods() && !processor.shouldProcessProperties()) return + if (!processor.shouldProcessMethods() && !processor.shouldProcessProperties()) return for (parent in place.parents()) { if (parent is GrMember) break diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt index c36dd0f77996..a1d352f67144 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt @@ -30,7 +30,7 @@ fun PsiScopeProcessor.shouldProcessDynamicProperties(): Boolean { return getHint(DynamicMembersHint.KEY)?.shouldProcessProperties() ?: false } -fun PsiScopeProcessor.shoudProcessMethods(): Boolean { +fun PsiScopeProcessor.shouldProcessMethods(): Boolean { return ResolveUtil.shouldProcessMethods(getHint(ElementClassHint.KEY)) } From ea095bf076e7deec64eebe34166d55ce7c4a4cd8 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Tue, 31 Oct 2017 16:12:49 +0300 Subject: [PATCH 03/43] [groovy] add base resolve result class with lazy staticsOk/accessible --- .../lang/resolve/BaseGroovyResolveResult.kt | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/BaseGroovyResolveResult.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/BaseGroovyResolveResult.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/BaseGroovyResolveResult.kt new file mode 100644 index 000000000000..06703eea3859 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/BaseGroovyResolveResult.kt @@ -0,0 +1,37 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMember +import com.intellij.psi.PsiModifierListOwner +import com.intellij.psi.PsiSubstitutor +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement +import org.jetbrains.plugins.groovy.lang.psi.util.GrStaticChecker +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil + +open class BaseGroovyResolveResult( + element: T, + protected val myPlace: PsiElement?, + private val myResolveContext: PsiElement? = null, + protected val mySubstitutor: PsiSubstitutor = PsiSubstitutor.EMPTY +) : ElementGroovyResult(element) { + + private val accessible by lazy(LazyThreadSafetyMode.PUBLICATION) { + myElement !is PsiMember || myPlace == null || PsiUtil.isAccessible(myPlace, myElement) + } + + override fun isAccessible(): Boolean = accessible + + private val staticsOk by lazy(LazyThreadSafetyMode.PUBLICATION) { + myResolveContext is GrImportStatement || + myElement !is PsiModifierListOwner || + myPlace == null || + GrStaticChecker.isStaticsOK(myElement, myPlace, myResolveContext, false) + } + + override fun isStaticsOK(): Boolean = staticsOk + + override fun getCurrentFileResolveContext(): PsiElement? = myResolveContext + + override fun getSubstitutor(): PsiSubstitutor = mySubstitutor +} From 040c1cef000fc6dd7570e992535925b54dc52434 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Tue, 31 Oct 2017 16:14:44 +0300 Subject: [PATCH 04/43] [groovy] add ClassProcessor and ClassResolveResult It: - stops on first found class; - ignores type parameters; - returns ClassResolveResult-s, which are parameterized by PsiClass. --- .../groovy/lang/resolve/ClassResolveResult.kt | 13 ++++++++ .../lang/resolve/GrResolverProcessor.kt | 13 ++++++++ .../lang/resolve/processors/ClassProcessor.kt | 32 +++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ClassResolveResult.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrResolverProcessor.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ClassProcessor.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ClassResolveResult.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ClassResolveResult.kt new file mode 100644 index 000000000000..c031cc7cbd26 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ClassResolveResult.kt @@ -0,0 +1,13 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve + +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiSubstitutor + +class ClassResolveResult( + element: PsiClass, + place: PsiElement?, + resolveContext: PsiElement?, + substitutor: PsiSubstitutor +) : BaseGroovyResolveResult(element, place, resolveContext, substitutor) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrResolverProcessor.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrResolverProcessor.kt new file mode 100644 index 000000000000..051a0571b5b0 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrResolverProcessor.kt @@ -0,0 +1,13 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve + +import com.intellij.psi.scope.PsiScopeProcessor +import com.intellij.util.containers.ContainerUtil.toArray +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult + +interface GrResolverProcessor : PsiScopeProcessor { + + val results: List + + val resultsArray: Array get() = toArray(results, GroovyResolveResult.EMPTY_ARRAY) +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ClassProcessor.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ClassProcessor.kt new file mode 100644 index 000000000000..3f42f28e12e4 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ClassProcessor.kt @@ -0,0 +1,32 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve.processors + +import com.intellij.psi.* +import com.intellij.util.SmartList +import org.jetbrains.plugins.groovy.lang.resolve.ClassResolveResult +import org.jetbrains.plugins.groovy.lang.resolve.GrResolverProcessor +import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint.RESOLVE_KINDS_CLASS + +class ClassProcessor( + name: String, + private val place: PsiElement?, + private val typeArguments: Array = PsiType.EMPTY_ARRAY +) : GrScopeProcessorWithHints(name, RESOLVE_KINDS_CLASS), GrResolverProcessor { + + private val myResults = SmartList() + override val results: List get() = myResults + + override fun execute(element: PsiElement, state: ResolveState): Boolean { + val clazz = element as? PsiClass ?: return true + if (clazz is PsiTypeParameter) return true + + val substitutor = state.get(PsiSubstitutor.KEY) ?: PsiSubstitutor.EMPTY + myResults += ClassResolveResult( + element = clazz, + place = place, + resolveContext = state.get(ClassHint.RESOLVE_CONTEXT), + substitutor = substitutor.putAll(clazz, typeArguments) + ) + return false + } +} From 2583d42fbf711c091a549a52b9d602e47008979a Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Tue, 31 Oct 2017 16:16:57 +0300 Subject: [PATCH 05/43] [groovy] convert `qualifiedReferenceName` to internal ext property --- .../lang/resolve/GrReferenceResolveRunner.kt | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrReferenceResolveRunner.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrReferenceResolveRunner.kt index 07b39cb0c467..ba8c6a250713 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrReferenceResolveRunner.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrReferenceResolveRunner.kt @@ -181,7 +181,7 @@ private fun GrReferenceExpression.doResolvePackageOrClass(): PsiElement? { if (parent is GrMethodCall) return null val name = referenceName ?: return null if (name.isEmpty() || !name.first().isUpperCase()) return null - val qname = getQualifiedReferenceName() ?: return null + val qname = qualifiedReferenceName ?: return null return facade.findClass(qname, scope) } @@ -192,7 +192,7 @@ private fun GrReferenceExpression.doResolvePackageOrClass(): PsiElement? { for (parent in parents().drop(1)) { if (parent !is GrReferenceExpression) return null if (parent.resolveClass() == null) continue - val qname = getQualifiedReferenceName()!! + val qname = qualifiedReferenceName!! return facade.findPackage(qname) } @@ -208,15 +208,16 @@ private fun GrReferenceExpression.resolveLocalVariable(): GroovyResolveResult? { return processor.resolveResult } -private fun GrReferenceElement<*>.getQualifiedReferenceName(): String? { - val parts = mutableListOf() - var current = this - while (true) { - val name = current.referenceName ?: return null - parts.add(name) - val qualifier = current.qualifier ?: break - qualifier as? GrReferenceExpression ?: return null - current = qualifier +internal val GrReferenceElement<*>.qualifiedReferenceName: String? + get() { + val parts = mutableListOf() + var current = this + while (true) { + val name = current.referenceName ?: return null + parts.add(name) + val qualifier = current.qualifier ?: break + qualifier as? GrReferenceElement<*> ?: return null + current = qualifier + } + return parts.reversed().joinToString(separator = ".") } - return parts.reversed().joinToString(separator = ".") -} From 389ef25fa8bd232f240d2a2cae7055787980cd6b Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Tue, 31 Oct 2017 16:57:08 +0300 Subject: [PATCH 06/43] add flatten() which creates a view instead of copying all elements --- .../plugins/groovy/util/FlatCollection.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/FlatCollection.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/FlatCollection.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/FlatCollection.kt new file mode 100644 index 000000000000..d2b8708d181b --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/FlatCollection.kt @@ -0,0 +1,20 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.util + +import com.intellij.util.containers.FlatteningIterator + +/** + * Creates read-only flat view of [collections]. + * Changes in underlying collections will be reflected in this view. + */ +fun flatten(vararg collections: Collection): Collection = FlatCollection(collections) + +private class FlatCollection(private val collections: Array>) : AbstractCollection() { + + override val size: Int get() = collections.sumBy { it.size } + + override fun iterator(): Iterator = object : FlatteningIterator, T>(collections.iterator()) { + + override fun createValueIterator(group: Collection): Iterator = group.iterator() + } +} From d4a27c5adacebd6bdcfb9110ff4420ed43d367a6 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Tue, 31 Oct 2017 17:42:48 +0300 Subject: [PATCH 07/43] [groovy] revamp imports - add 4 classes representing each import kind; - split processing implementations between these 4 classes; - process declarations independently of import origin (either explicit import or implicit one); - change import processing order; - process default imports after all other imports are processed; - default imports are no longer contributed via extension due to their special status. --- .../toplevel/imports/GrImportStatement.java | 20 ++--- .../groovy/lang/psi/impl/GroovyFileImpl.java | 78 ++++++------------ .../imports/GrImportStatementImpl.java | 25 +++--- .../lang/psi/impl/utils/psiImportUtil.kt | 53 ++++++++++++ .../lang/resolve/DefaultImportContributor.kt | 39 --------- .../groovy/lang/resolve/ResolveUtil.kt | 39 +++++++++ .../lang/resolve/imports/GroovyFileImports.kt | 20 +++++ .../lang/resolve/imports/GroovyImport.kt | 38 +++++++++ .../lang/resolve/imports/RegularImport.kt | 55 +++++++++++++ .../groovy/lang/resolve/imports/StarImport.kt | 33 ++++++++ .../lang/resolve/imports/StaticImport.kt | 81 +++++++++++++++++++ .../lang/resolve/imports/StaticStarImport.kt | 36 +++++++++ .../imports/impl/GroovyFileImportsImpl.kt | 22 +++++ .../lang/resolve/imports/impl/NonFqnImport.kt | 26 ++++++ .../groovy/lang/resolve/imports/impl/impl.kt | 65 +++++++++++++++ .../lang/resolve/imports/impl/strategies.kt | 29 +++++++ .../groovy/lang/resolve/imports/imports.kt | 23 ++++++ plugins/groovy/src/META-INF/plugin.xml | 1 - 18 files changed, 561 insertions(+), 122 deletions(-) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/utils/psiImportUtil.kt delete mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/DefaultImportContributor.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyFileImports.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyImport.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StarImport.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticStarImport.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyFileImportsImpl.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/NonFqnImport.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/impl.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/strategies.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/imports.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/toplevel/imports/GrImportStatement.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/toplevel/imports/GrImportStatement.java index c4ef729064e6..17a30849d4c4 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/toplevel/imports/GrImportStatement.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/toplevel/imports/GrImportStatement.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2014 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports; @@ -24,6 +10,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.GrTopStatement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; +import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImport; /** * @author ilyas @@ -53,4 +40,7 @@ public interface GrImportStatement extends GrTopStatement { @Nullable PsiElement getAliasNameElement(); + + @Nullable + GroovyImport getImport(); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java index 934be614c4df..c106526124d7 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java @@ -5,7 +5,6 @@ package org.jetbrains.plugins.groovy.lang.psi.impl; import com.intellij.lang.ASTNode; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.PsiFileEx; import com.intellij.psi.impl.source.resolve.SymbolCollectingProcessor.ResultWithContext; @@ -15,6 +14,7 @@ import com.intellij.psi.scope.NameHint; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.stubs.StubElement; import com.intellij.psi.util.*; +import com.intellij.util.BooleanFunction; import com.intellij.util.IncorrectOperationException; import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; @@ -36,21 +36,25 @@ import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.GrTopStatement; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; -import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyImportHelper.ImportKind; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrBindingVariable; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightParameter; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; import org.jetbrains.plugins.groovy.lang.psi.stubs.GrFileStub; import org.jetbrains.plugins.groovy.lang.psi.stubs.GrPackageDefinitionStub; -import org.jetbrains.plugins.groovy.lang.resolve.ImplicitImportsKt; import org.jetbrains.plugins.groovy.lang.resolve.MethodTypeInferencer; -import org.jetbrains.plugins.groovy.lang.resolve.PackageSkippingProcessor; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; +import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyFileImports; +import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImport; import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint; import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolverProcessor; import java.util.concurrent.ConcurrentMap; +import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.processClassesInFile; +import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.processClassesInPackage; +import static org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImports.getDefaultImports; +import static org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImports.getImports; + /** * Implements all abstractions related to Groovy file * @@ -181,38 +185,31 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile, Ps return true; } - boolean processClasses = ResolveUtil.shouldProcessClasses(classHint); - - GrImportStatement[] importStatements = getImportStatements(); - if (!processImports(processor, state, lastParent, place, importStatements, ImportKind.ALIAS, false)) return false; - - GroovyScriptClass scriptClass = getScriptClass(); - if (scriptClass != null && StringUtil.isJavaIdentifier(scriptClass.getName())) { - - if (!(lastParent instanceof GrTypeDefinition)) { - if (!ResolveUtil.processClassDeclarations(scriptClass, processor, state, lastParent, place)) return false; + final BooleanFunction> processImports = imports -> { + for (GroovyImport anImport : imports) { + if (!anImport.processDeclarations(processor, state, place, this)) return false; } + return true; + }; - if (processClasses) { - if (!ResolveUtil.processElement(processor, scriptClass, state)) return false; - } + final GroovyScriptClass scriptClass = getScriptClass(); + if (scriptClass != null && !(lastParent instanceof GrTypeDefinition)) { + if (!ResolveUtil.processClassDeclarations(scriptClass, processor, state, lastParent, place)) return false; } - if (processClasses) { - for (GrTypeDefinition definition : getTypeDefinitions()) { - if (!ResolveUtil.processElement(processor, definition, state)) return false; - } - } + final GroovyFileImports imports = getImports(this); + if (!processImports.fun(imports.getRegularImports())) return false; + if (!processImports.fun(imports.getStaticImports())) return false; + if (!processClassesInFile(this, processor, state)) return false; if (ResolveUtil.shouldProcessProperties(classHint)) { if (!processChildrenScopes(processor, state, lastParent, place)) return false; } - if (!processImports(processor, state, lastParent, place, importStatements, ImportKind.ALIAS, true)) return false; - if (!processImports(processor, state, lastParent, place, importStatements, ImportKind.SIMPLE, null)) return false; - if (!processDeclarationsInPackage(processor, state, lastParent, place)) return false; - if (!processImports(processor, state, lastParent, place, importStatements, ImportKind.ON_DEMAND, null)) return false; - if (!ImplicitImportsKt.processImplicitImports(processor, state, lastParent, place, this)) return false; + if (!processClassesInPackage(this, processor, state, place)) return false; + if (!processImports.fun(imports.getStarImports())) return false; + if (!processImports.fun(imports.getStaticStarImports())) return false; + if (!processImports.fun(getDefaultImports())) return false; if (ResolveUtil.shouldProcessPackages(classHint)) { @@ -247,18 +244,8 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile, Ps public boolean isInScriptBody(PsiElement lastParent, PsiElement place) { return isScript() && - !(lastParent instanceof GrTypeDefinition) && - PsiTreeUtil.getParentOfType(place, GrTypeDefinition.class, false) == null; - } - - protected boolean processImports(PsiScopeProcessor processor, - @NotNull ResolveState state, - @Nullable PsiElement lastParent, - @NotNull PsiElement place, - @NotNull GrImportStatement[] importStatements, - @NotNull ImportKind kind, - @Nullable Boolean processStatic) { - return GroovyImportHelper.processImports(state, lastParent, place, processor, importStatements, kind, processStatic); + !(lastParent instanceof GrTypeDefinition) && + PsiTreeUtil.getParentOfType(place, GrTypeDefinition.class, false) == null; } @NotNull @@ -271,19 +258,6 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile, Ps return true; } - private boolean processDeclarationsInPackage(@NotNull PsiScopeProcessor processor, - @NotNull ResolveState state, - @Nullable PsiElement lastParent, - @NotNull PsiElement place) { - if (ResolveUtil.shouldProcessClasses(processor.getHint(ElementClassHint.KEY))) { - PsiPackage aPackage = JavaPsiFacade.getInstance(getProject()).findPackage(getPackageName()); - if (aPackage != null) { - return aPackage.processDeclarations(new PackageSkippingProcessor(processor), state, lastParent, place); - } - } - return true; - } - private boolean processChildrenScopes(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, @Nullable PsiElement lastParent, diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/toplevel/imports/GrImportStatementImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/toplevel/imports/GrImportStatementImpl.java index 939af2b19cc6..ef230ea2f0fe 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/toplevel/imports/GrImportStatementImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/toplevel/imports/GrImportStatementImpl.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.psi.impl.toplevel.imports; @@ -44,6 +30,7 @@ import org.jetbrains.plugins.groovy.lang.psi.stubs.GrImportStatementStub; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; +import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImport; import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint; import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolverProcessor; import org.jetbrains.plugins.groovy.lang.resolve.processors.StaticMembersFilteringProcessor; @@ -54,6 +41,7 @@ import java.util.List; import static com.intellij.psi.scope.ElementClassHint.DeclarationKind.CLASS; import static com.intellij.psi.scope.ElementClassHint.DeclarationKind.METHOD; import static com.intellij.util.containers.ContainerUtil.zip; +import static org.jetbrains.plugins.groovy.lang.psi.impl.utils.PsiImportUtil.createImportFromStatement; /** * @author ilyas @@ -82,6 +70,7 @@ public class GrImportStatementImpl extends GrStubElementBase = imports -} \ No newline at end of file diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt index a1d352f67144..2c43137d3dd8 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt @@ -1,12 +1,17 @@ // Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +@file:Suppress("LoopToCallChain") + package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.openapi.util.Key import com.intellij.psi.* import com.intellij.psi.scope.ElementClassHint +import com.intellij.psi.scope.ElementClassHint.DeclarationKind +import com.intellij.psi.scope.NameHint import com.intellij.psi.scope.PsiScopeProcessor import com.intellij.psi.util.CachedValueProvider.Result import com.intellij.psi.util.CachedValuesManager.getCachedValue +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.DefaultConstructor import org.jetbrains.plugins.groovy.lang.resolve.processors.DynamicMembersHint @@ -22,6 +27,13 @@ fun treeWalkUp(place: PsiElement, processor: PsiScopeProcessor, state: ResolveSt return ResolveUtil.treeWalkUp(place, place, processor, state) } +fun PsiScopeProcessor.checkName(name: String, state: ResolveState): Boolean { + val expectedName = getName(state) ?: return true + return expectedName == name +} + +fun PsiScopeProcessor.getName(state: ResolveState): String? = getHint(NameHint.KEY)?.getName(state) + fun shouldProcessDynamicMethods(processor: PsiScopeProcessor): Boolean { return processor.getHint(DynamicMembersHint.KEY)?.shouldProcessMethods() ?: false } @@ -34,6 +46,17 @@ fun PsiScopeProcessor.shouldProcessMethods(): Boolean { return ResolveUtil.shouldProcessMethods(getHint(ElementClassHint.KEY)) } +fun PsiScopeProcessor.shouldProcessClasses(): Boolean { + return ResolveUtil.shouldProcessClasses(getHint(ElementClassHint.KEY)) +} + +fun PsiScopeProcessor.shouldProcessMembers(): Boolean { + val hint = getHint(ElementClassHint.KEY) ?: return true + return hint.shouldProcess(DeclarationKind.CLASS) || + hint.shouldProcess(DeclarationKind.FIELD) || + hint.shouldProcess(DeclarationKind.METHOD) +} + fun PsiScopeProcessor.shouldProcessProperties(): Boolean { return this is GroovyResolverProcessor && isPropertyResolve } @@ -45,3 +68,19 @@ fun getDefaultConstructor(clazz: PsiClass): PsiMethod { Result.create(DefaultConstructor(clazz), clazz) } } + +fun GroovyFile.processClassesInFile(processor: PsiScopeProcessor, state: ResolveState): Boolean { + if (!processor.shouldProcessClasses()) return true + val scriptClass = scriptClass + if (scriptClass != null && !ResolveUtil.processElement(processor, scriptClass, state)) return false + for (definition in typeDefinitions) { + if (!ResolveUtil.processElement(processor, definition, state)) return false + } + return true +} + +fun GroovyFile.processClassesInPackage(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement = this): Boolean { + if (!processor.shouldProcessClasses()) return true + val aPackage = JavaPsiFacade.getInstance(project).findPackage(packageName) ?: return true + return aPackage.processDeclarations(PackageSkippingProcessor(processor), state, null, place) +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyFileImports.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyFileImports.kt new file mode 100644 index 000000000000..6d0e4f0455f5 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyFileImports.kt @@ -0,0 +1,20 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve.imports + +interface GroovyFileImports { + + val regularImports: Collection + + val staticImports: Collection + + val starImports: Collection + + val staticStarImports: Collection + + + val allImports: Collection + + val allNamedImports: Collection + + val allStarImports: Collection +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyImport.kt new file mode 100644 index 000000000000..18514813c5f3 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyImport.kt @@ -0,0 +1,38 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve.imports + +import com.intellij.psi.PsiElement +import com.intellij.psi.ResolveState +import com.intellij.psi.scope.PsiScopeProcessor +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement + +interface GroovyImport { + + /** + * Returns statement from which this import was created or `null` + */ + val statement: GrImportStatement? + + /** + * Resolves current import using [file] as a context + */ + fun resolve(file: GroovyFile): PsiElement? + + /** + * Feeds the processor elements available via this import + */ + fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFile): Boolean +} + +interface GroovyNamedImport : GroovyImport { + + val name: String + + val isAliased: Boolean +} + +interface GroovyStarImport : GroovyImport { + + val fqn: String +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt new file mode 100644 index 000000000000..46555336e7b6 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt @@ -0,0 +1,55 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve.imports + +import com.intellij.openapi.util.text.StringUtil.getShortName +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiElement +import com.intellij.psi.ResolveState +import com.intellij.psi.scope.PsiScopeProcessor +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement +import org.jetbrains.plugins.groovy.lang.resolve.checkName +import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint +import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessClasses + +/** + * Represents regular import, possibly aliased. + * + * Example: in `import com.foo.Bar as Baz`: + * - [classFqn] = `com.foo.Bar` + * - [name] = `Baz` + * - [isAliased] = `true` + * + * Example: in `import com.foo.Bar`: + * - [classFqn] = `com.foo.Bar` + * - [name] = `Bar` + * - [isAliased] = `false` + */ + +class RegularImport internal constructor( + override val statement: GrImportStatement?, + val classFqn: String, + override val name: String +) : GroovyNamedImport { + + constructor(fqn: String) : this(null, fqn, getShortName(fqn)) + constructor(fqn: String, name: String) : this(null, fqn, name) + + override val isAliased: Boolean = getShortName(classFqn) != name + + override fun resolve(file: GroovyFile): PsiClass? { + val facade = JavaPsiFacade.getInstance(file.project) + return facade.findClass(classFqn, file.resolveScope) + } + + override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFile): Boolean { + if (!processor.shouldProcessClasses()) return true + if (!processor.checkName(name, state)) return true + + val clazz = resolve(file) ?: return true + return processor.execute(clazz, state.put(ClassHint.RESOLVE_CONTEXT, statement)) + } + + override fun toString(): String = "import $classFqn as $name" +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StarImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StarImport.kt new file mode 100644 index 000000000000..ca5fcf6419ba --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StarImport.kt @@ -0,0 +1,33 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve.imports + +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiPackage +import com.intellij.psi.ResolveState +import com.intellij.psi.scope.PsiScopeProcessor +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement +import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint + +class StarImport internal constructor( + override val statement: GrImportStatement?, + val packageFqn: String +) : GroovyStarImport { + + constructor(packageFqn: String) : this(null, packageFqn) + + override val fqn: String get() = packageFqn + + override fun resolve(file: GroovyFile): PsiPackage? { + val facade = JavaPsiFacade.getInstance(file.project) + return facade.findPackage(packageFqn) + } + + override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFile): Boolean { + val pckg = resolve(file) ?: return true + return pckg.processDeclarations(processor, state.put(ClassHint.RESOLVE_CONTEXT, statement), null, place) + } + + override fun toString(): String = "import $packageFqn.*" +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt new file mode 100644 index 000000000000..7ff88083ce2a --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt @@ -0,0 +1,81 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve.imports + +import com.intellij.psi.PsiElement +import com.intellij.psi.ResolveState +import com.intellij.psi.scope.PsiScopeProcessor +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement +import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils.* +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil +import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.NonFqnImport +import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint +import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolverProcessor +import org.jetbrains.plugins.groovy.lang.resolve.processors.StaticMembersFilteringProcessor +import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessMembers + +/** + * Represents a static import, possibly aliased. + * + * Example: in `import static com.Foo.Bar as Baz`: + * - [classFqn] = `com.Foo` + * - [memberName] = `Bar` + * - [name] = `Baz` + * - [isAliased] = `true` + * + * Example: in `import static com.Foo.Bar`: + * - [classFqn] = `com.Foo` + * - [memberName] = `Bar` + * - [name] = `Bar` + * - [isAliased] = `false` + */ +class StaticImport internal constructor( + override val statement: GrImportStatement?, + override val classFqn: String, + val memberName: String, + override val name: String = memberName +) : NonFqnImport(), GroovyNamedImport { + + constructor(classFqn: String, memberName: String) : this(null, classFqn, memberName) + constructor(classFqn: String, memberName: String, name: String) : this(null, classFqn, memberName, name) + + override val isAliased: Boolean = memberName != name + + override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFile): Boolean { + if (!processor.shouldProcessMembers()) return true + val clazz = resolve(file) ?: return true + val stateWithContext = state.put(ClassHint.RESOLVE_CONTEXT, statement) + val namesMapping = namesMapping() + for (each in GroovyResolverProcessor.allProcessors(processor)) { + val hintName = ResolveUtil.getNameHint(each) + for ((memberName, alias) in namesMapping) { + if (hintName != null && hintName != alias) continue + val delegate = StaticMembersFilteringProcessor(each, memberName) + if (!clazz.processDeclarations(delegate, stateWithContext, null, place)) return false + } + } + return true + } + + override fun toString(): String = "import static $classFqn.$memberName as $name" + + private fun namesMapping() = namesMapping(memberName, name) + + companion object { + + private fun names(name: String): List = listOf( + name, + getGetterNameNonBoolean(name), + getGetterNameBoolean(name), + getSetterName(name) + ) + + private fun namesMapping(left: String, right: String): List> { + val leftNames = names(left) + val rightNames = if (left == right) leftNames + else names( + right) + return leftNames.zip(rightNames) + } + } +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticStarImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticStarImport.kt new file mode 100644 index 000000000000..481ea7e720b7 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticStarImport.kt @@ -0,0 +1,36 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +@file:Suppress("LoopToCallChain") + +package org.jetbrains.plugins.groovy.lang.resolve.imports + +import com.intellij.psi.PsiElement +import com.intellij.psi.ResolveState +import com.intellij.psi.scope.PsiScopeProcessor +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement +import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.NonFqnImport +import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint +import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolverProcessor +import org.jetbrains.plugins.groovy.lang.resolve.processors.StaticMembersFilteringProcessor + +class StaticStarImport internal constructor( + override val statement: GrImportStatement?, + override val classFqn: String +) : NonFqnImport(), GroovyStarImport { + + constructor(classFqn: String) : this(null, classFqn) + + override val fqn: String get() = classFqn + + override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFile): Boolean { + val clazz = resolve(file) ?: return true + val stateWithContext = state.put(ClassHint.RESOLVE_CONTEXT, statement) + for (each in GroovyResolverProcessor.allProcessors(processor)) { + val filteringProcessor = StaticMembersFilteringProcessor(each, null) + if (!clazz.processDeclarations(filteringProcessor, stateWithContext, null, place)) return false + } + return true + } + + override fun toString(): String = "import static $classFqn.*" +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyFileImportsImpl.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyFileImportsImpl.kt new file mode 100644 index 000000000000..a16acdeb72f0 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyFileImportsImpl.kt @@ -0,0 +1,22 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve.imports.impl + +import org.jetbrains.plugins.groovy.lang.resolve.imports.* +import org.jetbrains.plugins.groovy.util.flatten + +internal class GroovyFileImportsImpl( + override val regularImports: Collection, + override val staticImports: Collection, + override val starImports: Collection, + override val staticStarImports: Collection +) : GroovyFileImports { + + override val allNamedImports: Collection = flatten(regularImports, staticImports) + + override val allStarImports: Collection = flatten(starImports, staticStarImports) + + override val allImports: Collection = flatten(regularImports, staticImports, starImports, staticStarImports) + + override fun toString(): String = "Regular: ${regularImports.size}; static: ${staticImports.size}; " + + "*: ${starImports.size}; static *: ${staticStarImports.size}" +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/NonFqnImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/NonFqnImport.kt new file mode 100644 index 000000000000..ad9c69b13ed7 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/NonFqnImport.kt @@ -0,0 +1,26 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve.imports.impl + +import com.intellij.openapi.util.text.StringUtil +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiClass +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImport + +abstract class NonFqnImport : GroovyImport { + + abstract val classFqn: String + + override fun resolve(file: GroovyFile): PsiClass? { + val facade = JavaPsiFacade.getInstance(file.project) + val scope = file.resolveScope + + val clazz = facade.findClass(classFqn, scope) + if (clazz != null) return clazz + + if (StringUtil.getShortName(classFqn) != classFqn) return null + + val fqn = StringUtil.getQualifiedName(file.packageName, classFqn) + return facade.findClass(fqn, scope) + } +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/impl.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/impl.kt new file mode 100644 index 000000000000..a973c8965486 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/impl.kt @@ -0,0 +1,65 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve.imports.impl + +import com.intellij.openapi.util.text.StringUtil +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase +import org.jetbrains.plugins.groovy.lang.resolve.GrImportContributor +import org.jetbrains.plugins.groovy.lang.resolve.Import +import org.jetbrains.plugins.groovy.lang.resolve.ImportType +import org.jetbrains.plugins.groovy.lang.resolve.imports.* + +internal val defaultRegularImports = GroovyFileBase.IMPLICITLY_IMPORTED_CLASSES.map(::RegularImport) +internal val defaultStarImports = GroovyFileBase.IMPLICITLY_IMPORTED_PACKAGES.map(::StarImport) + +internal fun GroovyFile.doGetImports(): GroovyFileImports { + val regularImports = LinkedHashMap() + val starImports = LinkedHashMap() + val staticImports = LinkedHashMap() + val staticStarImports = LinkedHashMap() + + fun addImport(import: GroovyImport?) { + when (import) { + is RegularImport -> regularImports[import.name] = import + is StaticImport -> staticImports[import.name] = import + is StarImport -> starImports[import.packageFqn] = import + is StaticStarImport -> staticStarImports[import.classFqn] = import + null -> return + else -> unsupportedImport(import) + } + } + + for (statement in importStatements) { + addImport(statement.import) + } + + for (contributor in GrImportContributor.EP_NAME.extensions) { + contributor.getImports(this).forEach { + addImport(createImportFromContributor(it)) + } + } + + return GroovyFileImportsImpl( + regularImports.values.toList(), + staticImports.values.toList(), + starImports.values.toList(), + staticStarImports.values.toList() + ) +} + +private fun createImportFromContributor(contributedImport: Import): GroovyImport { + val type = contributedImport.type + val name = contributedImport.name + return when (type) { + ImportType.REGULAR -> RegularImport(name) + ImportType.STATIC -> { + val packageName = StringUtil.getPackageName(name) + val memberName = StringUtil.getShortName(name) + StaticImport(packageName, memberName) + } + ImportType.STAR -> StarImport(name) + ImportType.STATIC_STAR -> StaticStarImport(name) + } +} + +private fun unsupportedImport(import: GroovyImport): Nothing = error("Unsupported import. Class: ${import.javaClass}; toString: ${import}") diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/strategies.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/strategies.kt new file mode 100644 index 000000000000..98bf02b48e23 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/strategies.kt @@ -0,0 +1,29 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve.imports.impl + +import gnu.trove.TObjectHashingStrategy + +import org.jetbrains.plugins.groovy.lang.resolve.imports.RegularImport +import org.jetbrains.plugins.groovy.lang.resolve.imports.StarImport + +internal object RegularImportHashingStrategy : TObjectHashingStrategy { + + override fun equals(o1: RegularImport?, o2: RegularImport?): Boolean { + if (o1 === o2) return true + if (o1 == null || o2 == null) return false + return o1.classFqn == o2.classFqn && o1.name == o2.name + } + + override fun computeHashCode(o: RegularImport?): Int = if (o == null) 0 else 31 * o.classFqn.hashCode() + o.name.hashCode() +} + +internal object StarImportHashingStrategy : TObjectHashingStrategy { + + override fun equals(o1: StarImport?, o2: StarImport?): Boolean { + if (o1 === o2) return true + if (o1 == null || o2 == null) return false + return o1.fqn == o2.fqn + } + + override fun computeHashCode(o: StarImport?): Int = o?.fqn?.hashCode() ?: 0 +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/imports.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/imports.kt new file mode 100644 index 000000000000..e1bba8bfb6c1 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/imports.kt @@ -0,0 +1,23 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +@file:JvmName("GroovyImports") + +package org.jetbrains.plugins.groovy.lang.resolve.imports + +import com.intellij.psi.util.CachedValueProvider.Result +import com.intellij.psi.util.CachedValuesManager +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement +import org.jetbrains.plugins.groovy.lang.psi.util.ErrorUtil +import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.defaultRegularImports +import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.defaultStarImports +import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.doGetImports + +val defaultImports = defaultStarImports + defaultRegularImports + +fun GroovyFile.getImports(): GroovyFileImports { + return CachedValuesManager.getCachedValue(this) { + Result.create(doGetImports(), this) + } +} + +val GroovyFile.validImportStatements: List get() = importStatements.filterNot(ErrorUtil::containsError) diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 0cf8803d2921..0bdc8a002bd0 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -284,7 +284,6 @@ - From 2bccb34103301a09c79b8a3bec1b102e42f7c315 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Tue, 31 Oct 2017 17:46:22 +0300 Subject: [PATCH 08/43] [groovy] use new imports - delegate processDeclarations() to file in FromString processor, GroovyFile is responsible for import order; - cleanup GroovyImportHelper; - use new imports in `findAliasedName`. --- .../lang/psi/impl/GroovyImportHelper.java | 50 +------------------ .../FromStringHintProcessor.java | 39 ++------------- .../rename/RenameAliasedUsagesUtil.java | 47 +++++++---------- 3 files changed, 22 insertions(+), 114 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyImportHelper.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyImportHelper.java index e88227470497..43bfe14dd392 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyImportHelper.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyImportHelper.java @@ -1,30 +1,12 @@ -/* - * Copyright 2000-2016 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.psi.impl; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; -import com.intellij.psi.ResolveState; -import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; -import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; import org.jetbrains.plugins.groovy.lang.resolve.GrImportContributor; import org.jetbrains.plugins.groovy.lang.resolve.ImportType; @@ -35,12 +17,6 @@ import java.util.LinkedHashSet; */ public class GroovyImportHelper { - public enum ImportKind { - SIMPLE, - ON_DEMAND, - ALIAS; - } - public static boolean isImplicitlyImported(PsiElement element, String expectedName, GroovyFile file) { if (!(element instanceof PsiClass)) return false; @@ -76,28 +52,4 @@ public class GroovyImportHelper { return result; } - - public static boolean processImports(@NotNull ResolveState state, - @Nullable PsiElement lastParent, - @NotNull PsiElement place, - @NotNull PsiScopeProcessor importProcessor, - @NotNull GrImportStatement[] importStatements, - @NotNull ImportKind kind, - @Nullable Boolean processStatic) { - for (int i = importStatements.length - 1; i >= 0; i--) { - final GrImportStatement imp = importStatements[i]; - if (getImportKind(imp) != kind) continue; - if (processStatic != null && processStatic != imp.isStatic()) continue; - if (!imp.processDeclarations(importProcessor, state, lastParent, place)) return false; - } - return true; - } - - @Nullable - private static ImportKind getImportKind(GrImportStatement statement) { - if (statement.isOnDemand() && !statement.isAliasedImport()) return ImportKind.ON_DEMAND; - if (!statement.isOnDemand() && statement.isAliasedImport()) return ImportKind.ALIAS; - if (!statement.isAliasedImport() && !statement.isOnDemand()) return ImportKind.SIMPLE; - return null; - } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromStringHintProcessor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromStringHintProcessor.java index eebe969f090c..1eabc9efd2de 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromStringHintProcessor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromStringHintProcessor.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; import com.intellij.psi.*; @@ -25,7 +11,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.GroovyLanguage; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; -import org.jetbrains.plugins.groovy.lang.resolve.ImplicitImportsKt; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import java.util.List; @@ -58,6 +43,7 @@ public class FromStringHintProcessor extends SignatureHintProcessor { }); } + @NotNull public static PsiElement createContext(@NotNull PsiMethod method) { return new FromStringLightElement(method); } @@ -87,30 +73,13 @@ class FromStringLightElement extends LightElement { PsiClass containingClass = myMethod.getContainingClass(); if (containingClass != null) { - PsiTypeParameter[] parameters = containingClass.getTypeParameters(); + PsiTypeParameter[] parameters = containingClass.getTypeParameters(); for (PsiTypeParameter parameter : parameters) { if (!ResolveUtil.processElement(processor, parameter, state)) return false; } } - if (!ImplicitImportsKt.processImplicitImports(processor, state, lastParent, place, myFile)) { - return false; - } - - // Suppose place is 'MyClass' and MyClass belongs to default package. - // This reference will not be resolved, because context has no parents (it has no parents at all. - // See com.intellij.psi.impl.source.PsiJavaCodeReferenceElementImpl.OurGenericsResolver.resolve() - if (place instanceof PsiQualifiedReference) { - PsiQualifiedReference reference = (PsiQualifiedReference)place; - if (reference.getQualifier() == null && reference.getReferenceName() != null) { - PsiClass aClass = JavaPsiFacade.getInstance(getProject()).findClass(reference.getReferenceName(), getResolveScope()); - if (aClass != null && !ResolveUtil.processElement(processor, aClass, state)) { - return false; - } - } - } - - return true; + return myFile.processDeclarations(processor, state, lastParent, place); } @Override diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/RenameAliasedUsagesUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/RenameAliasedUsagesUtil.java index 1be85cc15df7..c93d41fabf36 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/RenameAliasedUsagesUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/RenameAliasedUsagesUtil.java @@ -1,18 +1,4 @@ -/* - * 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.refactoring.rename; import com.intellij.psi.*; @@ -22,6 +8,9 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; +import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyFileImports; +import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImports; +import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyNamedImport; import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassResolverProcessor; import org.jetbrains.plugins.groovy.lang.resolve.processors.MethodResolverProcessor; import org.jetbrains.plugins.groovy.lang.resolve.processors.PropertyResolverProcessor; @@ -57,7 +46,7 @@ public class RenameAliasedUsagesUtil { public static boolean skipReference(PsiElement member, Map aliases, PsiElement element) { final PsiFile containingFile = element.getContainingFile(); - if (containingFile instanceof GroovyFile && findAliasedName(aliases, (GroovyFile)element.getContainingFile(), member) != EMPTY_ALIAS) { + if (containingFile instanceof GroovyFile && findAliasedName(aliases, ((GroovyFile)containingFile), member) != EMPTY_ALIAS) { if (PsiTreeUtil.getParentOfType(element, GrImportStatement.class, true) != null) return false; return true; } @@ -67,21 +56,19 @@ public class RenameAliasedUsagesUtil { private static String findAliasedName(Map map, GroovyFile containingFile, PsiElement elementToResolve) { final String s = map.get(containingFile); if (s != null) return s; - final GrImportStatement[] imports = containingFile.getImportStatements(); + final PsiManager manager = elementToResolve.getManager(); - for (GrImportStatement anImport : imports) { - if (anImport.isAliasedImport()) { - final ResolverProcessor processor = getProcessor(elementToResolve, containingFile); - anImport.processDeclarations(processor, ResolveState.initial(), null, containingFile); - final GroovyResolveResult[] results = processor.getCandidates(); - for (GroovyResolveResult result : results) { - if (manager.areElementsEquivalent(elementToResolve, result.getElement())) { - final String importedName = anImport.getImportedName(); - if (importedName != null) { - map.put(containingFile, importedName); - return importedName; - } - } + final ResolverProcessor processor = getProcessor(elementToResolve, containingFile); + final GroovyFileImports fileImports = GroovyImports.getImports(containingFile); + for (GroovyNamedImport anImport : fileImports.getAllNamedImports()) { + if (!anImport.isAliased()) continue; + anImport.processDeclarations(processor, ResolveState.initial(), containingFile, containingFile); + final GroovyResolveResult[] results = processor.getCandidates(); + for (GroovyResolveResult result : results) { + if (manager.areElementsEquivalent(elementToResolve, result.getElement())) { + final String importedName = anImport.getName(); + map.put(containingFile, importedName); + return importedName; } } } From 22f54781f7420ff720523525813489afa778c4bd Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Tue, 31 Oct 2017 17:49:14 +0300 Subject: [PATCH 09/43] [groovy] compute unused import declarations using new imports --- .../local/GroovyPostHighlightingPass.java | 30 +-- .../lang/psi/util/GroovyImportUtil.java | 30 +-- .../groovy/lang/resolve/implicitImports.kt | 75 +------ .../lang/resolve/imports/unusedImports.kt | 195 ++++++++++++++++++ ...roovyImportOptimizerRefactoringHelper.java | 21 +- .../move/GroovyMoveClassToInnerHandler.java | 32 +-- 6 files changed, 219 insertions(+), 164 deletions(-) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/unusedImports.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java index 38ff50b983c6..ae1bf08d756a 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/local/GroovyPostHighlightingPass.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.codeInspection.local; @@ -60,22 +46,22 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyImportUtil; -import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import java.util.*; +import static org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyUnusedImportUtil.unusedImports; + /** * @author ilyas */ public class GroovyPostHighlightingPass extends TextEditorHighlightingPass { - private final GroovyFile myFile; - private final Editor myEditor; + private final @NotNull GroovyFile myFile; + private final @NotNull Editor myEditor; private volatile Set myUnusedImports; private volatile List myUnusedDeclarations; - public GroovyPostHighlightingPass(GroovyFile file, Editor editor) { + public GroovyPostHighlightingPass(@NotNull GroovyFile file, @NotNull Editor editor) { super(file.getProject(), editor.getDocument(), true); myFile = file; myEditor = editor; @@ -171,9 +157,7 @@ public class GroovyPostHighlightingPass extends TextEditorHighlightingPass { super.visitElement(element); } }); - final Set unusedImports = new HashSet<>(PsiUtil.getValidImportStatements(myFile)); - unusedImports.removeAll(GroovyImportUtil.findUsedImports(myFile)); - myUnusedImports = unusedImports; + myUnusedImports = unusedImports(myFile); if (deadCodeEnabled) { for (GrParameter parameter : usedParams.keySet()) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyImportUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyImportUtil.java index e7392501ea97..bccfbe894b0e 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyImportUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyImportUtil.java @@ -5,7 +5,6 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; @@ -16,12 +15,11 @@ import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatem import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyImportHelper; -import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassResolverProcessor; import java.util.Map; import java.util.Set; -import static org.jetbrains.plugins.groovy.lang.psi.impl.GroovyImportHelper.ImportKind.ON_DEMAND; +import static org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyUnusedImportUtil.unusedImports; public class GroovyImportUtil { public static void processFile(@Nullable final PsiFile file, @@ -70,7 +68,7 @@ public class GroovyImportUtil { if (context instanceof GrImportStatement) { final GrImportStatement importStatement = (GrImportStatement)context; - if (usedImports != null && isImportUsed(refElement, resolved)) { + if (usedImports != null) { usedImports.add(importStatement); } if (GroovyImportHelper.isImplicitlyImported(resolved, refName, (GroovyFile)file)) { @@ -151,21 +149,6 @@ public class GroovyImportUtil { } } } - - /** - * checks if import for implicitly imported class is needed - */ - private boolean isImportUsed(GrReferenceElement refElement, PsiElement resolved) { - if (GroovyImportHelper.isImplicitlyImported(resolved, refElement.getReferenceName(), (GroovyFile)file)) { - final ClassResolverProcessor processor = new ClassResolverProcessor(refElement.getReferenceName(), refElement); - GroovyImportHelper - .processImports(ResolveState.initial(), null, refElement, processor, ((GroovyFile)file).getImportStatements(), ON_DEMAND, null); - if (!processor.hasCandidates()) { - return false; - } - } - return true; - } }); final Set importsToCheck = ContainerUtil.newLinkedHashSet(PsiUtil.getValidImportStatements((GroovyFile)file)); @@ -227,6 +210,9 @@ public class GroovyImportUtil { } }); } + if (usedImports != null) { + usedImports.removeAll(unusedImports((GroovyFile)file)); + } } @Nullable @@ -252,10 +238,4 @@ public class GroovyImportUtil { } return null; } - - public static Set findUsedImports(GroovyFile file) { - Set usedImports = new HashSet<>(); - processFile(file, null, null, usedImports, null, null, null, null, null); - return usedImports; - } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/implicitImports.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/implicitImports.kt index 57e0cdd0d036..75ac86ad266e 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/implicitImports.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/implicitImports.kt @@ -1,24 +1,6 @@ -/* - * Copyright 2000-2016 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.resolve -import com.intellij.openapi.util.text.StringUtil -import com.intellij.psi.* -import com.intellij.psi.scope.DelegatingScopeProcessor -import com.intellij.psi.scope.PsiScopeProcessor import org.jetbrains.plugins.groovy.lang.psi.GroovyFile class Import( @@ -55,58 +37,3 @@ abstract class GrImportContributorBase : GrImportContributor { } } } - -fun getImplicitImports(file: GroovyFile): Collection = GrImportContributor.EP_NAME.extensions.flatMap { it.getImports(file) } - -fun processImplicitImports(processor: PsiScopeProcessor, - state: ResolveState, - lastParent: PsiElement?, - place: PsiElement, - file: GroovyFile): Boolean { - val hint = processor.getHint(com.intellij.psi.scope.ElementClassHint.KEY) - val facade = JavaPsiFacade.getInstance(file.project) - - val packageSkipper = lazy(LazyThreadSafetyMode.NONE) { PackageSkippingProcessor(processor) } - val staticMemberFilter = lazy(LazyThreadSafetyMode.NONE) { - object : DelegatingScopeProcessor(processor) { - override fun execute(element: PsiElement, state: ResolveState): Boolean { - return element !is PsiMember || !element.hasModifierProperty(PsiModifier.STATIC) || super.execute(element, state) - } - } - } - - loop@for (implicitImport in getImplicitImports(file)) { - when (implicitImport.type) { - ImportType.REGULAR -> { - if (!ResolveUtil.shouldProcessClasses(hint)) continue@loop - val clazz = facade.findClass(implicitImport.name, file.resolveScope) ?: continue@loop - if (!ResolveUtil.processElement(processor, clazz, state)) return false - } - ImportType.STATIC -> { - val className = StringUtil.getPackageName(implicitImport.name) - val memberName = StringUtil.getShortName(implicitImport.name) - if (StringUtil.isEmptyOrSpaces(className) || StringUtil.isEmptyOrSpaces(memberName)) continue@loop - val clazz = facade.findClass(className, file.resolveScope) ?: continue@loop - if (ResolveUtil.shouldProcessMethods (hint)) { - for (method in clazz.findMethodsByName(memberName, true)) { - if (!ResolveUtil.processElement(processor, method, state)) return false - } - } - if (ResolveUtil.shouldProcessProperties(hint)) { - val field = clazz.findFieldByName(memberName, true) ?: continue@loop - if (!ResolveUtil.processElement(processor, field, state)) return false - } - } - ImportType.STAR -> { - val pckg = facade.findPackage(implicitImport.name) ?: continue@loop - if (!pckg.processDeclarations(packageSkipper.value, state, lastParent, place)) return false - } - ImportType.STATIC_STAR -> { - val clazz = facade.findClass(implicitImport.name, file.resolveScope) ?: continue@loop - if (!clazz.processDeclarations(staticMemberFilter.value, state, lastParent, place)) return false - } - } - } - - return true -} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/unusedImports.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/unusedImports.kt new file mode 100644 index 000000000000..124d2993d75b --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/unusedImports.kt @@ -0,0 +1,195 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +@file:JvmName("GroovyUnusedImportUtil") +@file:Suppress("LoopToCallChain") + +package org.jetbrains.plugins.groovy.lang.resolve.imports + +import com.intellij.openapi.util.text.StringUtil.getPackageName +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiRecursiveElementWalkingVisitor +import com.intellij.psi.ResolveState +import com.intellij.util.containers.HashSet +import gnu.trove.THashSet +import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition +import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.RegularImportHashingStrategy +import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.StarImportHashingStrategy +import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.defaultRegularImports +import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.defaultStarImports +import org.jetbrains.plugins.groovy.lang.resolve.processClassesInFile +import org.jetbrains.plugins.groovy.lang.resolve.processClassesInPackage +import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassProcessor + +private val defaultRegularImportsSet = THashSet(defaultRegularImports, RegularImportHashingStrategy) +private val defaultStarImportsSet = THashSet(defaultStarImports, StarImportHashingStrategy) + +fun unusedImports(file: GroovyFile): Set { + val result = file.validImportStatements.toMutableSet() + result -= usedImports(file) + return result +} + +fun usedImports(file: GroovyFile): Set { + val imports = file.getImports() + + val (referencedStatements, unresolvedReferenceNames) = run { + val searcher = ReferencedImportsSearcher() + file.accept(searcher) + searcher.results + } + assertShadowed(file, referencedStatements) + + val usedStatements = HashSet(referencedStatements) + usedStatements -= imports.findUnusedStarImportStatements() + usedStatements -= imports.findUnusedStaticImportStatements() + usedStatements -= imports.findUnusedRegularImportStatements(file) + + if (!unresolvedReferenceNames.isEmpty()) { + usedStatements.addAll(imports.findUnresolvedNamedImports(file, unresolvedReferenceNames)) + usedStatements.addAll(imports.findUnresolvedStarImports(file)) + } + + return usedStatements +} + +private class ReferencedImportsSearcher : PsiRecursiveElementWalkingVisitor() { + + private val referencedStatements = HashSet() + private val unresolvedReferenceNames = LinkedHashSet() + + val results: Pair, Set> get() = referencedStatements to unresolvedReferenceNames + + override fun visitElement(element: PsiElement) { + if (element !is GrImportStatement && element !is GrPackageDefinition) { + super.visitElement(element) + } + if (element is GrReferenceElement<*>) { + visitRefElement(element) + } + } + + private fun visitRefElement(refElement: GrReferenceElement<*>) { + if (refElement.isQualified) return + + val refName = refElement.referenceName + if (refName == null || "super" == refName) return + + val results = refElement.multiResolve(false) + if (results.isEmpty()) { + unresolvedReferenceNames.add(refName) + } + else { + for (result in results) { + val resolveContext = result.currentFileResolveContext + if (resolveContext is GrImportStatement) { + referencedStatements.add(resolveContext as GrImportStatement?) + } + } + } + } +} + + +private fun assertShadowed(file: GroovyFile, referencedStatements: Collection) { + val allStatements = file.validImportStatements + val shadowedStatements = allStatements - file.getImports().allImports.getStatements() + val intersection = referencedStatements.intersect(shadowedStatements) + assert(intersection.isEmpty()) { + """|Shadowed imports found in referenced. + |Intersection: + |${intersection.map { it.text }} + |Shadowed: + |${shadowedStatements.map { it.text }} + |Referenced: + |${referencedStatements.map { it.text }}""".trimMargin() + } +} + +private fun GroovyFileImports.findUnusedRegularImportStatements(file: GroovyFile): List = findUnusedRegularImports( + file).getStatements() + +private fun GroovyFileImports.findUnusedStaticImportStatements(): List = findUnusedStaticImports().getStatements() + +private fun GroovyFileImports.findUnusedStarImportStatements(): List = findUnusedStarImports().getStatements() + +private fun GroovyFileImports.findUnusedRegularImports(file: GroovyFile): List { + return regularImports.filter { + val statement = it.statement + statement != null && isUnused(file, statement, it) + } +} + +private fun GroovyFileImports.findUnusedStaticImports(): List { + return staticImports.filter { + it.statement != null && isUnused(it) + } +} + +private fun GroovyFileImports.findUnusedStarImports(): List { + return starImports.filter { + it.statement != null && isUnused(it) + } +} + +private fun GroovyFileImports.isUnused(file: GroovyFile, statement: GrImportStatement, import: RegularImport): Boolean { + if (import.isAliased) return false + + val processor = ClassProcessor(import.name, file) + val state = ResolveState.initial() + + for (_import in staticImports) { + if (!_import.processDeclarations(processor, state, statement, file)) return false + } + + val starImport = StarImport(getPackageName(import.classFqn)) + if (starImport.packageFqn == file.packageName) return true + + if (!file.processClassesInFile(processor, state)) return false + if (!file.processClassesInPackage(processor, state)) return false + + if (starImport in starImports) return true + + for (_import in starImports) { + if (!_import.processDeclarations(processor, state, statement, file)) return false + } + + for (_import in staticStarImports) { + if (!_import.processDeclarations(processor, state, statement, file)) return false + } + + val results = processor.results + assert(results.isEmpty()) { + "Processor returned true, but there are ${results.size} results: $results" + } + + return import in defaultRegularImportsSet || starImport in defaultStarImportsSet +} + +private fun GroovyFileImports.isUnused(import: StaticImport): Boolean { + if (import.isAliased) return false + return StaticStarImport(import.classFqn) in staticStarImports +} + +private fun isUnused(import: StarImport): Boolean { + return import in defaultStarImportsSet +} + +private fun Collection.getStatements(): List { + return mapNotNull { + it.statement + } +} + +private fun GroovyFileImports.findUnresolvedNamedImports(file: GroovyFile, names: Collection): Collection { + return allNamedImports.filter { + it.statement != null && it.name in names && it.resolve(file) == null + }.getStatements() +} + +private fun GroovyFileImports.findUnresolvedStarImports(file: GroovyFile): List { + return starImports.filter { + it.statement != null && it.resolve(file) == null + }.getStatements() +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyImportOptimizerRefactoringHelper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyImportOptimizerRefactoringHelper.java index 3588381dc929..e9999feb8a81 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyImportOptimizerRefactoringHelper.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyImportOptimizerRefactoringHelper.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2014 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.refactoring; @@ -30,7 +16,6 @@ import com.intellij.usageView.UsageInfo; import com.intellij.util.containers.hash.HashSet; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyImportUtil; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import java.util.HashMap; @@ -38,6 +23,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import static org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyUnusedImportUtil.usedImports; + /** * @author Maxim.Medvedev */ @@ -77,7 +64,7 @@ public class GroovyImportOptimizerRefactoringHelper implements RefactoringHelper progressIndicator.setFraction((double)i++/total); } ApplicationManager.getApplication().runReadAction(() -> { - final Set usedImports = GroovyImportUtil.findUsedImports(file); + final Set usedImports = usedImports(file); final List validImports = PsiUtil.getValidImportStatements(file); redundants.put(file, Pair.create(validImports, usedImports)); }); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/GroovyMoveClassToInnerHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/GroovyMoveClassToInnerHandler.java index 78159ed4dd4a..fffdb282d9ee 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/GroovyMoveClassToInnerHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/GroovyMoveClassToInnerHandler.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.refactoring.move; import com.intellij.openapi.diagnostic.Logger; @@ -37,11 +23,12 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrRefere import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyImportUtil; import org.jetbrains.plugins.groovy.util.GroovyChangeContextUtil; import java.util.*; +import static org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyUnusedImportUtil.unusedImports; + /** * @author Max Medvedev */ @@ -192,15 +179,10 @@ public class GroovyMoveClassToInnerHandler implements MoveClassToInnerHandler { @Override public void removeRedundantImports(PsiFile targetClassFile) { - if (targetClassFile instanceof GroovyFile) { - GroovyFile file = (GroovyFile)targetClassFile; - final Set usedImports = GroovyImportUtil.findUsedImports(file); - final List validImports = org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.getValidImportStatements(file); - for (GrImportStatement importStatement : validImports) { - if (!usedImports.contains(importStatement)) { - file.removeImport(importStatement); - } - } + if (!(targetClassFile instanceof GroovyFile)) return; + final GroovyFile file = (GroovyFile)targetClassFile; + for (GrImportStatement unusedImport : unusedImports(file)) { + file.removeImport(unusedImport); } } } From 4d6989979576cb36d4f319a278690b1d50e4520f Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Thu, 2 Nov 2017 21:39:57 +0300 Subject: [PATCH 10/43] [groovy] disallow import of classes in default package --- .../plugins/groovy/lang/resolve/imports/RegularImport.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt index 46555336e7b6..2c6586f69a7b 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt @@ -26,7 +26,6 @@ import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessClasses * - [name] = `Bar` * - [isAliased] = `false` */ - class RegularImport internal constructor( override val statement: GrImportStatement?, val classFqn: String, @@ -39,6 +38,7 @@ class RegularImport internal constructor( override val isAliased: Boolean = getShortName(classFqn) != name override fun resolve(file: GroovyFile): PsiClass? { + if (!file.packageName.isEmpty() && '.' !in classFqn) return null val facade = JavaPsiFacade.getInstance(file.project) return facade.findClass(classFqn, file.resolveScope) } From c7e9e99131b763f0727268f4ecd72a2d585d7869 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Thu, 2 Nov 2017 21:43:28 +0300 Subject: [PATCH 11/43] [groovy] add ability to ask processor if it expects type parameters - add GroovyResolveKind.TYPE_PARAMETER; - add GroovyResolveKind.Hint interface and a key; - add utility function to check processor; - use it in processing of class & methods declarations. --- .../typedef/members/GrMethodBaseImpl.java | 24 ++++------------- .../groovy/lang/psi/util/GrClassImplUtil.java | 8 ++++-- .../groovy/lang/resolve/ResolveUtil.kt | 7 +++++ .../resolve/processors/GroovyResolveKind.java | 27 ++++++++----------- 4 files changed, 29 insertions(+), 37 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java index d9334c1f0702..c2930f5c0539 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.psi.impl.statements.typedef.members; import com.intellij.lang.ASTNode; @@ -79,6 +65,8 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.shouldProcessTypeParameters; + /** * @author ilyas */ @@ -173,15 +161,13 @@ public abstract class GrMethodBaseImpl extends GrStubElementBase i @NotNull ResolveState state, @Nullable PsiElement lastParent, @NotNull PsiElement place) { - ElementClassHint classHint = processor.getHint(ElementClassHint.KEY); - - if (ResolveUtil.shouldProcessClasses(classHint)) { + if (shouldProcessTypeParameters(processor)) { for (final GrTypeParameter typeParameter : getTypeParameters()) { if (!ResolveUtil.processElement(processor, typeParameter, state)) return false; } } - if (ResolveUtil.shouldProcessProperties(classHint)) { + if (ResolveUtil.shouldProcessProperties(processor.getHint(ElementClassHint.KEY))) { for (final GrParameter parameter : getParameters()) { if (!ResolveUtil.processElement(processor, parameter, state)) return false; } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java index ff5bf8fb1d92..34470ed42a5e 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java @@ -48,6 +48,8 @@ import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import java.util.*; +import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.shouldProcessTypeParameters; + /** * @author Maxim.Medvedev */ @@ -204,8 +206,10 @@ public class GrClassImplUtil { } } - for (final PsiTypeParameter typeParameter : grType.getTypeParameters()) { - if (!ResolveUtil.processElement(processor, typeParameter, state)) return false; + if (shouldProcessTypeParameters(processor)) { + for (final PsiTypeParameter typeParameter : grType.getTypeParameters()) { + if (!ResolveUtil.processElement(processor, typeParameter, state)) return false; + } } NameHint nameHint = processor.getHint(NameHint.KEY); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt index 2c43137d3dd8..7a284efd594c 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt @@ -15,6 +15,7 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyFile import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.DefaultConstructor import org.jetbrains.plugins.groovy.lang.resolve.processors.DynamicMembersHint +import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolveKind import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolverProcessor @JvmField val NON_CODE = Key.create("groovy.process.non.code.members") @@ -57,6 +58,12 @@ fun PsiScopeProcessor.shouldProcessMembers(): Boolean { hint.shouldProcess(DeclarationKind.METHOD) } +fun PsiScopeProcessor.shouldProcessTypeParameters(): Boolean { + if (shouldProcessClasses()) return true + val groovyKindHint = getHint(GroovyResolveKind.HINT_KEY) ?: return true + return groovyKindHint.shouldProcess(GroovyResolveKind.TYPE_PARAMETER) +} + fun PsiScopeProcessor.shouldProcessProperties(): Boolean { return this is GroovyResolverProcessor && isPropertyResolve } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolveKind.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolveKind.java index 3d96b50660d2..35f29e54acd4 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolveKind.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolveKind.java @@ -1,27 +1,15 @@ -/* - * Copyright 2000-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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.resolve.processors; +import com.intellij.openapi.util.Key; import com.intellij.psi.scope.ElementClassHint.DeclarationKind; +import org.jetbrains.annotations.NotNull; import java.util.Collections; import java.util.EnumSet; import java.util.Set; -enum GroovyResolveKind { +public enum GroovyResolveKind { VARIABLE(DeclarationKind.VARIABLE), BINDING(DeclarationKind.VARIABLE), @@ -29,6 +17,7 @@ enum GroovyResolveKind { METHOD(DeclarationKind.METHOD), FIELD(DeclarationKind.FIELD), PROPERTY(DeclarationKind.METHOD, DeclarationKind.FIELD), + TYPE_PARAMETER(DeclarationKind.CLASS), CLASS(DeclarationKind.CLASS), PACKAGE(DeclarationKind.PACKAGE); @@ -37,4 +26,10 @@ enum GroovyResolveKind { GroovyResolveKind(DeclarationKind kind, DeclarationKind... kinds) { declarationKinds = Collections.unmodifiableSet(EnumSet.of(kind, kinds)); } + + public interface Hint { + boolean shouldProcess(@NotNull GroovyResolveKind kind); + } + + public static final Key HINT_KEY = Key.create("groovy.resolve.kind.hint"); } From e246842f18827d0b7c82be28fc1c21679c3b8f8e Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Thu, 2 Nov 2017 21:44:59 +0300 Subject: [PATCH 12/43] [groovy] add base interface for resolvers --- .../plugins/groovy/lang/resolve/GroovyResolver.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GroovyResolver.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GroovyResolver.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GroovyResolver.kt new file mode 100644 index 000000000000..a01155d8ecb2 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GroovyResolver.kt @@ -0,0 +1,13 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve + +import com.intellij.psi.impl.source.resolve.ResolveCache.AbstractResolver +import org.jetbrains.annotations.ApiStatus.Experimental +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyPolyVariantReference +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult + +@Experimental +interface GroovyResolver : AbstractResolver> { + + override fun resolve(ref: T, incomplete: Boolean): Collection +} From a0ace7e846e234c108ea9b05687f8df6396895d8 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Thu, 2 Nov 2017 21:46:52 +0300 Subject: [PATCH 13/43] [groovy] add collecting scope processor --- .../processors/CollectElementsProcessor.kt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/CollectElementsProcessor.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/CollectElementsProcessor.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/CollectElementsProcessor.kt new file mode 100644 index 000000000000..e5a88fc52272 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/CollectElementsProcessor.kt @@ -0,0 +1,17 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve.processors + +import com.intellij.psi.PsiElement +import com.intellij.psi.ResolveState +import com.intellij.psi.scope.BaseScopeProcessor + +class CollectElementsProcessor : BaseScopeProcessor() { + + private val myResults = mutableListOf() + val results: List get() = myResults + + override fun execute(element: PsiElement, state: ResolveState): Boolean { + myResults += element + return true + } +} From fede7f4688c821a14e873c4c740782f4e9429963 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Thu, 2 Nov 2017 21:47:59 +0300 Subject: [PATCH 14/43] [groovy] add type parameters processor This processor accepts type parameters only. --- .../processors/TypeParameterProcessor.kt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/TypeParameterProcessor.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/TypeParameterProcessor.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/TypeParameterProcessor.kt new file mode 100644 index 000000000000..65be9f832c4b --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/TypeParameterProcessor.kt @@ -0,0 +1,36 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve.processors + +import com.intellij.openapi.util.Key +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiTypeParameter +import com.intellij.psi.ResolveState +import org.jetbrains.plugins.groovy.lang.resolve.ElementGroovyResult +import org.jetbrains.plugins.groovy.lang.resolve.GrResolverProcessor + +class TypeParameterProcessor(name: String) : GrScopeProcessorWithHints(name, emptySet()), + GrResolverProcessor>, + GroovyResolveKind.Hint { + + private var myResult: ElementGroovyResult? = null + override val results: List> + get() = myResult.let { result -> + if (result == null) emptyList() else listOf(result) + } + + override fun execute(element: PsiElement, state: ResolveState): Boolean { + element as? PsiTypeParameter ?: return true + myResult = ElementGroovyResult(element) + return false + } + + @Suppress("UNCHECKED_CAST") + override fun getHint(hintKey: Key): T? { + return when (hintKey) { + GroovyResolveKind.HINT_KEY -> this as T + else -> super.getHint(hintKey) + } + } + + override fun shouldProcess(kind: GroovyResolveKind): Boolean = kind == GroovyResolveKind.TYPE_PARAMETER +} From 6b12dee7767eae9a6e98adfd32e7452768877fe9 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Thu, 2 Nov 2017 21:56:20 +0300 Subject: [PATCH 15/43] [groovy] fix/rewrite resolution of code references It's a rewrite actually. Now resolution order follows the compiler's ResolveVisitor. Bunch of code extracted to separate file and prepared to be used with reference expressions. Also now isAccessible/isStaticsOk are not computed during resolve. Instead, place is saved, and they are computed on-demand. --- .../types/GrCodeReferenceElementImpl.java | 4 +- .../groovy/lang/psi/util/psiTreeUtil.kt | 26 +- .../GrCodeReferencePolyVariantResolver.kt | 17 + .../lang/resolve/GrCodeReferenceResolver.kt | 300 ++++++++++++++++++ .../plugins/groovy/lang/resolve/collapsing.kt | 19 ++ .../GroovyClassNameCompletionTest.groovy | 26 +- .../lang/resolve/ResolveClassTest.groovy | 23 +- .../highlighting/ExtendingOwnInner.groovy | 2 +- 8 files changed, 366 insertions(+), 51 deletions(-) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferencePolyVariantResolver.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/collapsing.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java index ee4710404c3d..f489514713aa 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java @@ -32,6 +32,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ElementGroovyResult; +import org.jetbrains.plugins.groovy.lang.resolve.GrCodeReferencePolyVariantResolver; import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassResolverProcessor; import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor; @@ -456,7 +457,8 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl parent.javaClass !in types } } + +inline fun T.skipSameTypeParents(): Pair { + var lastParent: T = this + var parent: PsiElement? = parent + while (parent is T) { + lastParent = parent + parent = parent.parent + } + return Pair(parent, lastParent) +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferencePolyVariantResolver.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferencePolyVariantResolver.kt new file mode 100644 index 000000000000..dd307098c40d --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferencePolyVariantResolver.kt @@ -0,0 +1,17 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve + +import com.intellij.psi.impl.source.resolve.ResolveCache.PolyVariantResolver +import com.intellij.util.containers.ContainerUtil +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement + +/** + * Wrapper returning an array of GroovyResolveResult + */ +internal object GrCodeReferencePolyVariantResolver : PolyVariantResolver { + + override fun resolve(t: GrCodeReferenceElement, incompleteCode: Boolean): Array { + return ContainerUtil.toArray(GrCodeReferenceResolver.resolve(t, incompleteCode), GroovyResolveResult.EMPTY_ARRAY) + } +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt new file mode 100644 index 000000000000..66904d7f87d5 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt @@ -0,0 +1,300 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +@file:Suppress("LoopToCallChain") + +package org.jetbrains.plugins.groovy.lang.resolve + +import com.intellij.psi.* +import com.intellij.psi.scope.PsiScopeProcessor +import com.intellij.psi.util.parentOfType +import com.intellij.util.SmartList +import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult +import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrExtendsClause +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrImplementsClause +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement +import org.jetbrains.plugins.groovy.lang.psi.util.skipSameTypeParents +import org.jetbrains.plugins.groovy.lang.psi.util.treeWalkUp +import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImport +import org.jetbrains.plugins.groovy.lang.resolve.imports.StarImport +import org.jetbrains.plugins.groovy.lang.resolve.imports.StaticImport +import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassProcessor +import org.jetbrains.plugins.groovy.lang.resolve.processors.CollectElementsProcessor +import org.jetbrains.plugins.groovy.lang.resolve.processors.TypeParameterProcessor + +// https://issues.apache.org/jira/browse/GROOVY-8358 +// https://issues.apache.org/jira/browse/GROOVY-8359 +// https://issues.apache.org/jira/browse/GROOVY-8361 +// https://issues.apache.org/jira/browse/GROOVY-8362 +// https://issues.apache.org/jira/browse/GROOVY-8364 +// https://issues.apache.org/jira/browse/GROOVY-8365 + +internal object GrCodeReferenceResolver : GroovyResolver { + + override fun resolve(ref: GrCodeReferenceElement, incomplete: Boolean): Collection { + val kind = ref.getKind() + @Suppress("UnnecessaryVariable") + val results = when (kind) { + CodeReferenceKind.PACKAGE_REFERENCE -> ref.resolveAsPackageReference() + CodeReferenceKind.IMPORT_REFERENCE -> ref.resolveAsImportReference() + CodeReferenceKind.REFERENCE -> ref.resolveReference() + } + return results + } +} + +private enum class CodeReferenceKind { + PACKAGE_REFERENCE, + IMPORT_REFERENCE, + REFERENCE +} + +private fun GrCodeReferenceElement.getKind(): CodeReferenceKind { + val parent = parent + return when (parent) { + is GrPackageDefinition -> CodeReferenceKind.PACKAGE_REFERENCE + is GrImportStatement -> CodeReferenceKind.IMPORT_REFERENCE + is GrCodeReferenceElement -> parent.getKind() + else -> CodeReferenceKind.REFERENCE + } +} + +private fun GrCodeReferenceElement.resolveAsPackageReference(): Collection { + val fqn = qualifiedReferenceName ?: return emptyList() + val pckg = JavaPsiFacade.getInstance(project).findPackage(fqn) ?: return emptyList() + return listOf(ElementGroovyResult(pckg)) +} + +private fun GrCodeReferenceElement.resolveAsImportReference(): Collection { + val file = containingFile as? GroovyFile ?: return emptyList() + + val statement = parentOfType() ?: return emptyList() + val topLevelReference = statement.importReference ?: return emptyList() + val import = statement.import ?: return emptyList() + + if (this === topLevelReference) { + return if (import is StaticImport) { + resolveStaticImportReference(file, import) + } + else { + resolveImportReference(file, import) + } + } + if (parent === topLevelReference && import is StaticImport) { + return resolveImportReference(file, import) + } + if (import is StarImport) { + // reference inside star import + return resolveAsPackageReference() + } + + val clazz = import.resolve(file) as? PsiClass + val classReference = if (import is StaticImport) topLevelReference.qualifier else topLevelReference + if (clazz == null || classReference == null) return resolveAsPackageReference() + return resolveAsPartOfFqn(classReference, clazz) +} + +private fun resolveStaticImportReference(file: GroovyFile, import: StaticImport): Collection { + val processor = CollectElementsProcessor() + import.processDeclarations(processor, ResolveState.initial(), file, file) + return processor.results.collapseReflectedMethods().collapseAccessors().map(::ElementGroovyResult) +} + +private fun resolveImportReference(file: GroovyFile, import: GroovyImport): Collection { + val resolved = import.resolve(file) ?: return emptyList() + return listOf(ElementGroovyResult(resolved)) +} + +private fun GrCodeReferenceElement.resolveReference(): Collection { + val name = referenceName ?: return emptyList() + + if (canResolveToTypeParameter()) { + val typeParameters = resolveToTypeParameter(this, name) + if (typeParameters.isNotEmpty()) return typeParameters + } + + val (_, outerMostReference) = skipSameTypeParents() + if (outerMostReference !== this) { + val fqnReferencedClass = outerMostReference.resolveClassFqn() + if (fqnReferencedClass != null) { + return resolveAsPartOfFqn(outerMostReference, fqnReferencedClass) + } + } + else if (isQualified) { + val clazz = resolveClassFqn() + if (clazz != null) { + val substitutor = PsiSubstitutor.EMPTY.putAll(clazz, typeArguments) + return listOf(ClassResolveResult(clazz, this, null, substitutor)) + } + } + + val processor = ClassProcessor(name, this, typeArguments) + val state = ResolveState.initial() + processClasses(processor, state) + val classes = processor.results + if (classes.isNotEmpty()) return classes + + if (canResolveToPackage()) { + val packages = resolveAsPackageReference() + if (packages.isNotEmpty()) return packages + } + + return emptyList() +} + +private fun GrReferenceElement<*>.canResolveToTypeParameter(): Boolean { + if (isQualified) return false + val parent = parent + return parent !is GrReferenceElement<*> && + parent !is GrExtendsClause && + parent !is GrImplementsClause && + parent !is GrAnnotation && + parent !is GrImportStatement && + parent !is GrNewExpression && + parent !is GrAnonymousClassDefinition && + parent !is GrCodeReferenceElement +} + +private fun resolveToTypeParameter(place: PsiElement, name: String): Collection { + val processor = TypeParameterProcessor(name) + place.treeWalkUp(processor) + return processor.results +} + +private fun GrReferenceElement<*>.canResolveToPackage(): Boolean = parent is GrReferenceElement<*> + +private fun GrCodeReferenceElement.resolveAsPartOfFqn(reference: GrCodeReferenceElement, clazz: PsiClass): Collection { + var currentReference = reference + var currentElement: PsiNamedElement = clazz + while (currentReference !== this) { + currentReference = currentReference.qualifier ?: return emptyList() + val e: PsiNamedElement? = when (currentElement) { + is PsiClass -> currentElement.containingClass ?: currentElement.getPackage() + is PsiPackage -> currentElement.parentPackage + else -> null + } + currentElement = e ?: return emptyList() + } + return listOf(BaseGroovyResolveResult(currentElement, this, null)) +} + +private fun PsiClass.getPackage(): PsiPackage? { + val file = containingFile + val name = (file as? PsiClassOwner)?.packageName ?: return null + return JavaPsiFacade.getInstance(file.project).findPackage(name) +} + +@Suppress("LiftReturnOrAssignment") +private fun GrCodeReferenceElement.processClasses(processor: PsiScopeProcessor, state: ResolveState): Boolean { + val qualifier = qualifier + if (qualifier == null) { + return processAsUnqualifiedType(processor, state) + } + else { + return processQualifier(qualifier, processor, state) + } +} + +private fun GrCodeReferenceElement.processAsUnqualifiedType(processor: PsiScopeProcessor, state: ResolveState): Boolean { + return processInnerClasses(processor, state) && + containingFile.treeWalkUp(processor, state, this) +} + +private fun GrCodeReferenceElement.processQualifier(qualifier: GrCodeReferenceElement, + processor: PsiScopeProcessor, + state: ResolveState): Boolean { + for (result in qualifier.multiResolve(false)) { + val clazz = result.element as? PsiClass ?: continue + if (!processInnersInHierarchy(clazz, processor, state.put(PsiSubstitutor.KEY, result.substitutor), this)) return false + } + return true +} + +private fun GrReferenceElement<*>.resolveClassFqn(): PsiClass? { + val fqn = qualifiedReferenceName ?: return null + return JavaPsiFacade.getInstance(project).findClass(fqn, resolveScope) +} + +private fun GrReferenceElement<*>.processInnerClasses(processor: PsiScopeProcessor, state: ResolveState): Boolean { + val currentClass = parentOfType() ?: return true + + if (canResolveToInnerClassOrCurrentClass()) { + if (!processInnersInHierarchy(currentClass, processor, state, this)) return false + } + + val outers = currentClass.collectOuterClasses().reversed() + for (outer in outers) { + if (!processInnerClassesInClassAndInterfaces(outer, false, processor, state, this)) return false + } + return true +} + +private fun GrReferenceElement<*>.canResolveToInnerClassOrCurrentClass(): Boolean { + val parent = parent + return parent !is GrExtendsClause && + parent !is GrImplementsClause && + (parent !is GrAnnotation || parent.classReference != this) && // annotation's can't be inner classes of current class + (parent !is GrAnonymousClassDefinition || parent.baseClassReferenceGroovy != this) +} + +private fun processInnersInHierarchy(clazz: PsiClass, + processor: PsiScopeProcessor, + state: ResolveState, + place: PsiElement): Boolean { + if (!processInnerClassesInClassAndInterfaces(clazz, false, processor, state, place)) return false + + var superClass: PsiClass? = clazz.superClass + while (superClass != null) { + if (!processInnerClassesInClassAndInterfaces(superClass, true, processor, state, place)) return false + superClass = superClass.superClass + } + + return true +} + +private fun processInnerClassesInClassAndInterfaces(clazz: PsiClass, + includeSynthetic: Boolean, + processor: PsiScopeProcessor, + state: ResolveState, + place: PsiElement): Boolean { + val name = processor.getName(state) + if (name == null) { + for (inner in CollectClassMembersUtil.getInnerClasses(clazz, includeSynthetic)) { + if (!processor.execute(inner, state)) return false + } + } + else { + val inner = if (includeSynthetic) { + clazz.findInnerClassByName(name, false) + } + else { + val inners = (clazz as? GrTypeDefinition)?.codeInnerClasses ?: clazz.innerClasses + inners.find { it.name == name } + } + if (inner != null) { + if (!processor.execute(inner, state)) return false + } + } + + for (anInterface in clazz.interfaces) { + if (!anInterface.processDeclarations(processor, state, null, place)) return false + } + + return true +} + +private fun GrTypeDefinition.collectOuterClasses(): List { + val result = SmartList() + var current: GrTypeDefinition? = containingClass as? GrTypeDefinition + while (current != null) { + result += current + current = current.containingClass as? GrTypeDefinition + } + return result +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/collapsing.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/collapsing.kt new file mode 100644 index 000000000000..e8f64723c01f --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/collapsing.kt @@ -0,0 +1,19 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve + +import com.intellij.psi.PsiElement +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrReflectedMethod + +@Suppress("RemoveExplicitTypeArguments") +fun Collection.collapseReflectedMethods(): Collection { + return mapTo(mutableSetOf()) { + (it as? GrReflectedMethod)?.baseMethod ?: it + } +} + +fun Collection.collapseAccessors(): Collection { + val fields = filterIsInstance() + return filter { it !is GrAccessorMethod || it.property !in fields } +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy index 2ff8c14500bb..2bfd94d1b5ab 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.completion @@ -81,7 +67,10 @@ class GroovyClassNameCompletionTest extends LightCodeInsightFixtureTestCase { myFixture.configureByText("a.groovy", "FBa") complete() myFixture.type '.'.charAt(0) - myFixture.checkResult "a.FooBar.a" + myFixture.checkResult '''\ +import a.FooBar + +FooBar.a''' } private LookupElement[] complete() { @@ -93,7 +82,10 @@ class GroovyClassNameCompletionTest extends LightCodeInsightFixtureTestCase { myFixture.configureByText("a.groovy", "FBGDa") myFixture.complete(CompletionType.BASIC, 2) myFixture.type '.' - myFixture.checkResult "a.FooBarGooDoo.a" + myFixture.checkResult '''\ +import a.FooBarGooDoo + +FooBarGooDoo.a''' } void testDelegateBasicToClassNameAutoinsert() throws Exception { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.groovy index 6b03da2ee665..f53256a4db8d 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.groovy @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.psi.* @@ -113,7 +99,7 @@ class ResolveClassTest extends GroovyResolveTestCase { void testInnerClassUsageInsideOuterSubclass() throws Throwable { doTest() } - void testInnerClassOfInterface() { assertNull(resolve()) } + void testInnerClassOfInterface() { doTest() } void testInnerClassOfClassInSubClass1() { assertNull(resolve()) } @@ -211,6 +197,9 @@ interface Super { assertInstanceOf resolve("A.groovy"), PsiClass } + /** + * https://issues.apache.org/jira/browse/GROOVY-8364 + */ void testPreferImportsToInheritance() { myFixture.addClass("package java.util; public class MyMap { static interface Entry {} } ") myFixture.addClass("package java.util; public class MainMap { static interface Entry {} } ") @@ -223,7 +212,7 @@ public class Test extends MyMap { } """) def target = myFixture.file.findReferenceAt(myFixture.editor.caretModel.offset).resolve() - assert assertInstanceOf(target, PsiClass).qualifiedName == 'java.util.MainMap.Entry' + assert assertInstanceOf(target, PsiClass).qualifiedName == 'java.util.MyMap.Entry' } void testPreferLastImportedAlias() { diff --git a/plugins/groovy/testdata/highlighting/ExtendingOwnInner.groovy b/plugins/groovy/testdata/highlighting/ExtendingOwnInner.groovy index f3a365427711..dc7614199e4b 100644 --- a/plugins/groovy/testdata/highlighting/ExtendingOwnInner.groovy +++ b/plugins/groovy/testdata/highlighting/ExtendingOwnInner.groovy @@ -1,3 +1,3 @@ -class Foo extends Inner implements Unknown { +class Foo extends Inner implements Unknown { static class Inner {} } \ No newline at end of file From f82ce0f5f5b9bb91b85d79a17adac3f4a571b31a Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 3 Nov 2017 12:06:38 +0300 Subject: [PATCH 16/43] [groovy] cleanup code reference element --- .../types/GrCodeReferenceElementImpl.java | 232 +----------------- 1 file changed, 6 insertions(+), 226 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java index f489514713aa..130547452864 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java @@ -6,19 +6,15 @@ import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; -import com.intellij.psi.impl.source.resolve.ResolveCache; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocReferenceElement; import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; -import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; @@ -27,21 +23,8 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeArgumentList; import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper; import org.jetbrains.plugins.groovy.lang.psi.impl.GrReferenceElementImpl; -import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; -import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; -import org.jetbrains.plugins.groovy.lang.resolve.ElementGroovyResult; import org.jetbrains.plugins.groovy.lang.resolve.GrCodeReferencePolyVariantResolver; -import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassResolverProcessor; -import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor; - -import java.util.ArrayList; -import java.util.List; - -import static org.jetbrains.plugins.groovy.lang.psi.util.PsiTreeUtilKt.treeWalkUp; -import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil.collapseReflectedMethodsSimple; -import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil.filterAccessorMethods; /** * @author: Dmitry.Krasilschikov @@ -151,12 +134,14 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl { - - @Override - @NotNull - public GroovyResolveResult[] resolve(@NotNull GrCodeReferenceElementImpl reference, boolean incompleteCode) { - if (reference.getReferenceName() == null) return GroovyResolveResult.EMPTY_ARRAY; - final GroovyResolveResult[] results = _resolve(reference, reference.getManager(), reference.getKind(false)); - if (results.length == 0) return results; - - List imported = new ArrayList<>(); - final PsiType[] args = reference.getTypeArguments(); - for (int i = 0; i < results.length; i++) { - GroovyResolveResult result = results[i]; - final PsiElement element = result.getElement(); - if (element instanceof PsiClass) { - final PsiSubstitutor substitutor = result.getSubstitutor(); - final PsiSubstitutor newSubstitutor = substitutor.putAll((PsiClass)element, args); - PsiElement context = result.getCurrentFileResolveContext(); - GroovyResolveResultImpl newResult = - new GroovyResolveResultImpl(element, context, null, newSubstitutor, result.isAccessible(), result.isStaticsOK()); - results[i] = newResult; - if (context instanceof GrImportStatement) { - imported.add(newResult); - } - } - } - if (!imported.isEmpty()) { - return imported.toArray(new GroovyResolveResult[imported.size()]); - } - - return results; - } - - @NotNull - private static GroovyResolveResult[] _resolve(@NotNull GrCodeReferenceElementImpl ref, - @NotNull PsiManager manager, - @NotNull ReferenceKind kind) { - final String refName = ref.getReferenceName(); - if (refName == null) { - return GroovyResolveResult.EMPTY_ARRAY; - } - - switch (kind) { - case CLASS_OR_PACKAGE_FQ: - case CLASS_FQ: - case PACKAGE_FQ: { - String qName = PsiUtil.getQualifiedReferenceText(ref); - LOG.assertTrue(qName != null, ref.getText()); - final PsiElement element = resolveClassOrPackagePreferInner(ref, kind, qName, JavaPsiFacade.getInstance(manager.getProject())); - if (element instanceof PsiClass || element instanceof PsiPackage) { - final GroovyResolveResult result = new ElementGroovyResult<>(element); - return new GroovyResolveResult[]{result}; - } - return GroovyResolveResult.EMPTY_ARRAY; - } - - case CLASS: { - ResolverProcessor processor = new ClassResolverProcessor(refName, ref); - GrCodeReferenceElement qualifier = ref.getQualifier(); - if (qualifier != null) { - PsiElement qualifierResolved = qualifier.resolve(); - if (qualifierResolved instanceof PsiPackage || qualifierResolved instanceof PsiClass) { - qualifierResolved.processDeclarations(processor, ResolveState.initial(), null, ref); - return processor.getCandidates(); - } - } - else { - // if ref is an annotation name reference we should not process declarations of annotated elements - // because inner annotations are not permitted and it can cause infinite recursion - PsiElement placeToStartWalking = isAnnotationRef(ref) ? getContainingFileSkippingStubFiles(ref) : ref; - if (placeToStartWalking != null) { - treeWalkUp(placeToStartWalking, processor, ResolveState.initial(), ref); - GroovyResolveResult[] candidates = processor.getCandidates(); - if (candidates.length > 0) return candidates; - } - } - - break; - } - - case CLASS_OR_PACKAGE: { - GroovyResolveResult[] classResult = _resolve(ref, manager, ReferenceKind.CLASS); - - if (classResult.length == 1 && !classResult[0].isAccessible()) { - GroovyResolveResult[] packageResult = _resolve(ref, manager, ReferenceKind.PACKAGE_FQ); - if (packageResult.length != 0) { - return packageResult; - } - } - else if (classResult.length == 0) { - return _resolve(ref, manager, ReferenceKind.PACKAGE_FQ); - } - - return classResult; - } - case STATIC_MEMBER_FQ: { - final GrCodeReferenceElement qualifier = ref.getQualifier(); - if (qualifier == null) break; - - final PsiElement resolved = qualifier.resolve(); - if (!(resolved instanceof PsiClass)) break; - - final PsiClass clazz = (PsiClass)resolved; - - final List result = new ArrayList<>(); - processFields(refName, clazz, result); - processMethods(refName, clazz, result); - processInnerClasses(refName, clazz, result); - processAccessors(refName, clazz, result); - return collapseReflectedMethodsSimple(result).toArray(GroovyResolveResult.EMPTY_ARRAY); - } - } - - return GroovyResolveResult.EMPTY_ARRAY; - } - - @Nullable - private static PsiElement resolveClassOrPackagePreferInner(@NotNull GrCodeReferenceElementImpl ref, - @NotNull ReferenceKind kind, - String qName, - JavaPsiFacade facade) { - if (kind == ReferenceKind.CLASS_OR_PACKAGE_FQ || kind == ReferenceKind.CLASS_FQ) { - final PsiFile file = ref.getContainingFile(); - boolean qualified = qName.indexOf('.') > 0; - if (qualified || file instanceof GroovyFile && ((GroovyFile)file).getPackageName().isEmpty()) { - //prefer inner classes, because groovyc does that as well - PsiElement container = qualified ? resolveClassOrPackagePreferInner(ref, kind, StringUtil.getPackageName(qName), facade) : null; - PsiClass aClass = container instanceof PsiClass ? ((PsiClass)container).findInnerClassByName(StringUtil.getShortName(qName), true) : null; - if (aClass == null) { - aClass = facade.findClass(qName, ref.getResolveScope()); - } - if (aClass != null) { - return aClass; - } - } - } - - if (kind == ReferenceKind.CLASS_OR_PACKAGE_FQ || kind == ReferenceKind.PACKAGE_FQ) { - return facade.findPackage(qName); - } - - return null; - } - - private static PsiFile getContainingFileSkippingStubFiles(GrCodeReferenceElementImpl ref) { - PsiFile file = ref.getContainingFile(); - while (file != null && !file.isPhysical() && file.getContext() != null) { - PsiElement context = file.getContext(); - file = context.getContainingFile(); - } - return file; - } - - private static boolean isAnnotationRef(GrCodeReferenceElement ref) { - final PsiElement parent = ref.getParent(); - return parent instanceof GrAnnotation || parent instanceof GrCodeReferenceElement && isAnnotationRef((GrCodeReferenceElement)parent); - } - - private static void processAccessors(String refName, - PsiClass clazz, - List result) { - final List propertyResults = new ArrayList<>(); - final String booleanGetter = GroovyPropertyUtils.getGetterNameBoolean(refName); - final String nonBooleanGetter = GroovyPropertyUtils.getGetterNameNonBoolean(refName); - final String setter = GroovyPropertyUtils.getSetterName(refName); - - processMethods(booleanGetter, clazz, propertyResults); - processMethods(nonBooleanGetter, clazz, propertyResults); - processMethods(setter, clazz, propertyResults); - result.addAll(filterAccessorMethods(propertyResults)); - } - - private static void processInnerClasses(String refName, - PsiClass clazz, - List result) { - final PsiClass innerClass = clazz.findInnerClassByName(refName, true); - if (innerClass != null && innerClass.hasModifierProperty(PsiModifier.STATIC)) { - result.add(new ElementGroovyResult<>(innerClass)); - } - } - - private static void processFields(String refName, - PsiClass clazz, - List result) { - final PsiField field = clazz.findFieldByName(refName, true); - if (field != null && field.hasModifierProperty(PsiModifier.STATIC)) { - result.add(new ElementGroovyResult<>(field)); - } - } - - private static void processMethods(String refName, - PsiClass clazz, - List result) { - final PsiMethod[] methods = clazz.findMethodsByName(refName, true); - for (PsiMethod method : methods) { - if (method.hasModifierProperty(PsiModifier.STATIC)) { - result.add(new ElementGroovyResult<>(method)); - } - } - } - } - - private static final OurResolver RESOLVER = new OurResolver(); - @Override @NotNull public GroovyResolveResult[] multiResolve(boolean incompleteCode) { return TypeInferenceHelper.getCurrentContext().multiResolve(this, incompleteCode, GrCodeReferencePolyVariantResolver.INSTANCE); - //return TypeInferenceHelper.getCurrentContext().multiResolve(this, incompleteCode, RESOLVER); } @NotNull From 3fa3152986bb8da58cef29bbba85c261483ba309 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 3 Nov 2017 18:01:30 +0300 Subject: [PATCH 17/43] [groovy] move type parameter processing into type parameter list --- .../typedef/members/GrMethodBaseImpl.java | 9 ++--- .../impl/types/GrTypeParameterListImpl.java | 33 ++++++++++--------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java index c2930f5c0539..ddfd89d52d6f 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java @@ -65,8 +65,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.shouldProcessTypeParameters; - /** * @author ilyas */ @@ -161,11 +159,8 @@ public abstract class GrMethodBaseImpl extends GrStubElementBase i @NotNull ResolveState state, @Nullable PsiElement lastParent, @NotNull PsiElement place) { - if (shouldProcessTypeParameters(processor)) { - for (final GrTypeParameter typeParameter : getTypeParameters()) { - if (!ResolveUtil.processElement(processor, typeParameter, state)) return false; - } - } + final GrTypeParameterList list = getTypeParameterList(); + if (list != null && !list.processDeclarations(processor, state, lastParent, place)) return false; if (ResolveUtil.shouldProcessProperties(processor.getHint(ElementClassHint.KEY))) { for (final GrParameter parameter : getParameters()) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrTypeParameterListImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrTypeParameterListImpl.java index e8a86e9f03b2..db64936bc639 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrTypeParameterListImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrTypeParameterListImpl.java @@ -1,25 +1,13 @@ -/* - * Copyright 2000-2014 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.psi.impl.types; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiTypeParameter; +import com.intellij.psi.ResolveState; import com.intellij.psi.StubBasedPsiElement; +import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.stubs.EmptyStub; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; @@ -32,6 +20,9 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameter; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameterList; import org.jetbrains.plugins.groovy.lang.psi.impl.GrStubElementBase; +import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil.processElement; +import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.shouldProcessTypeParameters; + /** * @author ilyas */ @@ -123,4 +114,16 @@ public class GrTypeParameterListImpl extends GrStubElementBase implem } } } + + @Override + public boolean processDeclarations(@NotNull PsiScopeProcessor processor, + @NotNull ResolveState state, + PsiElement lastParent, + @NotNull PsiElement place) { + if (!shouldProcessTypeParameters(processor)) return true; + for (GrTypeParameter typeParameter : getTypeParameters()) { + if (!processElement(processor, typeParameter, state)) return false; + } + return true; + } } From 3d66c94a175a933a1dcd3d278d33278104006cc4 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 3 Nov 2017 18:04:01 +0300 Subject: [PATCH 18/43] [groovy] pass imported name into resolve context --- .../plugins/groovy/lang/resolve/imports/RegularImport.kt | 2 +- .../plugins/groovy/lang/resolve/imports/StaticImport.kt | 2 +- .../jetbrains/plugins/groovy/lang/resolve/imports/imports.kt | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt index 2c6586f69a7b..abfb4fd67dbd 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt @@ -48,7 +48,7 @@ class RegularImport internal constructor( if (!processor.checkName(name, state)) return true val clazz = resolve(file) ?: return true - return processor.execute(clazz, state.put(ClassHint.RESOLVE_CONTEXT, statement)) + return processor.execute(clazz, state.put(ClassHint.RESOLVE_CONTEXT, statement).put(importedNameKey, name)) } override fun toString(): String = "import $classFqn as $name" diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt index 7ff88083ce2a..7648d7c53be7 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt @@ -51,7 +51,7 @@ class StaticImport internal constructor( for ((memberName, alias) in namesMapping) { if (hintName != null && hintName != alias) continue val delegate = StaticMembersFilteringProcessor(each, memberName) - if (!clazz.processDeclarations(delegate, stateWithContext, null, place)) return false + if (!clazz.processDeclarations(delegate, stateWithContext.put(importedNameKey, alias), null, place)) return false } } return true diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/imports.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/imports.kt index e1bba8bfb6c1..185f48c3aaf6 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/imports.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/imports.kt @@ -3,6 +3,7 @@ package org.jetbrains.plugins.groovy.lang.resolve.imports +import com.intellij.openapi.util.Key import com.intellij.psi.util.CachedValueProvider.Result import com.intellij.psi.util.CachedValuesManager import org.jetbrains.plugins.groovy.lang.psi.GroovyFile @@ -12,6 +13,8 @@ import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.defaultRegularImpo import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.defaultStarImports import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.doGetImports +@JvmField +val importedNameKey = Key.create("groovy.imported.via.name") val defaultImports = defaultStarImports + defaultRegularImports fun GroovyFile.getImports(): GroovyFileImports { From 1bfa5892baba1b1e54b87e2af0a2ebb23b8af212 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 3 Nov 2017 18:05:38 +0300 Subject: [PATCH 19/43] [groovy] move reference-related utilities into separate file --- .../lang/resolve/GrCodeReferenceResolver.kt | 7 +----- .../lang/resolve/GrReferenceResolveRunner.kt | 15 ----------- .../plugins/groovy/lang/resolve/references.kt | 25 +++++++++++++++++++ 3 files changed, 26 insertions(+), 21 deletions(-) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/references.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt index 66904d7f87d5..c8f1dcc5533c 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt @@ -191,7 +191,7 @@ private fun PsiClass.getPackage(): PsiPackage? { } @Suppress("LiftReturnOrAssignment") -private fun GrCodeReferenceElement.processClasses(processor: PsiScopeProcessor, state: ResolveState): Boolean { +fun GrCodeReferenceElement.processClasses(processor: PsiScopeProcessor, state: ResolveState): Boolean { val qualifier = qualifier if (qualifier == null) { return processAsUnqualifiedType(processor, state) @@ -216,11 +216,6 @@ private fun GrCodeReferenceElement.processQualifier(qualifier: GrCodeReferenceEl return true } -private fun GrReferenceElement<*>.resolveClassFqn(): PsiClass? { - val fqn = qualifiedReferenceName ?: return null - return JavaPsiFacade.getInstance(project).findClass(fqn, resolveScope) -} - private fun GrReferenceElement<*>.processInnerClasses(processor: PsiScopeProcessor, state: ResolveState): Boolean { val currentClass = parentOfType() ?: return true diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrReferenceResolveRunner.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrReferenceResolveRunner.kt index ba8c6a250713..a15b14b9156c 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrReferenceResolveRunner.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrReferenceResolveRunner.kt @@ -7,7 +7,6 @@ import com.intellij.psi.util.InheritanceUtil import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.parents import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes -import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationArrayInitializer @@ -207,17 +206,3 @@ private fun GrReferenceExpression.resolveLocalVariable(): GroovyResolveResult? { treeWalkUp(processor, state) return processor.resolveResult } - -internal val GrReferenceElement<*>.qualifiedReferenceName: String? - get() { - val parts = mutableListOf() - var current = this - while (true) { - val name = current.referenceName ?: return null - parts.add(name) - val qualifier = current.qualifier ?: break - qualifier as? GrReferenceElement<*> ?: return null - current = qualifier - } - return parts.reversed().joinToString(separator = ".") - } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/references.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/references.kt new file mode 100644 index 000000000000..1bf29ee90ffc --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/references.kt @@ -0,0 +1,25 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve + +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiClass +import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement + +val GrReferenceElement<*>.qualifiedReferenceName: String? + get() { + val parts = mutableListOf() + var current = this + while (true) { + val name = current.referenceName ?: return null + parts.add(name) + val qualifier = current.qualifier ?: break + qualifier as? GrReferenceElement<*> ?: return null + current = qualifier + } + return parts.reversed().joinToString(separator = ".") + } + +fun GrReferenceElement<*>.resolveClassFqn(): PsiClass? { + val fqn = qualifiedReferenceName ?: return null + return JavaPsiFacade.getInstance(project).findClass(fqn, resolveScope) +} From 6f910c04362696ed697ecae7790f33eb2de954c5 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 3 Nov 2017 18:06:23 +0300 Subject: [PATCH 20/43] [groovy] add couple of overloads for GrDelegatingScopeProcessorWithHints --- .../GrDelegatingScopeProcessorWithHints.java | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GrDelegatingScopeProcessorWithHints.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GrDelegatingScopeProcessorWithHints.java index 2f3619ccde6d..212f94713e7c 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GrDelegatingScopeProcessorWithHints.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GrDelegatingScopeProcessorWithHints.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2015 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.resolve.processors; import com.intellij.openapi.util.Key; @@ -23,13 +9,24 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.EnumSet; +import java.util.Set; public class GrDelegatingScopeProcessorWithHints extends GrScopeProcessorWithHints { private final PsiScopeProcessor myDelegate; + public GrDelegatingScopeProcessorWithHints(@NotNull PsiScopeProcessor delegate, + @NotNull DeclarationKind target, + @NotNull DeclarationKind... targets) { + this(delegate, EnumSet.of(target, targets)); + } + + public GrDelegatingScopeProcessorWithHints(@NotNull PsiScopeProcessor delegate, @Nullable Set resolveTargets) { + this(delegate, null, resolveTargets); + } + public GrDelegatingScopeProcessorWithHints(@NotNull PsiScopeProcessor delegate, @Nullable String name, - @Nullable EnumSet resolveTargets) { + @Nullable Set resolveTargets) { super(name, resolveTargets); myDelegate = delegate; } From 695ddc900ad681772a6aabf2ede8c1dc29049459 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 3 Nov 2017 18:07:23 +0300 Subject: [PATCH 21/43] [groovy] make setupLookupBuilder public and return LookupElement --- .../lang/completion/GroovyCompletionUtil.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java index adb09a064dfb..bf123713cfdd 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java @@ -1,6 +1,4 @@ -// Copyright 2000-2017 JetBrains s.r.o. -// Use of this source code is governed by the Apache 2.0 license that can be -// found in the LICENSE file. +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.completion; @@ -331,10 +329,10 @@ public class GroovyCompletionUtil { return setupLookupBuilder(o, PsiSubstitutor.EMPTY, LookupElementBuilder.create(o, o.getName()), null); } - private static LookupElementBuilder setupLookupBuilder(PsiElement element, - PsiSubstitutor substitutor, - LookupElementBuilder builder, - @Nullable PsiElement position) { + public static LookupElement setupLookupBuilder(PsiElement element, + PsiSubstitutor substitutor, + LookupElementBuilder builder, + @Nullable PsiElement position) { builder = builder.withIcon(element.getIcon(Iconable.ICON_FLAG_VISIBILITY | Iconable.ICON_FLAG_READ_STATUS)) .withInsertHandler(GroovyInsertHandler.INSTANCE); builder = setTailText(element, builder, substitutor); @@ -609,7 +607,8 @@ public class GroovyCompletionUtil { public static void processVariants(GrReferenceElement referenceElement, PrefixMatcher matcher, CompletionParameters parameters, Consumer consumer) { if (referenceElement instanceof GrCodeReferenceElementImpl) { - CompleteCodeReferenceElement.processVariants((GrCodeReferenceElementImpl)referenceElement, consumer, matcher); + CompleteReferenceElementKt.complete((GrCodeReferenceElement)referenceElement, matcher, consumer); + //CompleteCodeReferenceElement.processVariants((GrCodeReferenceElementImpl)referenceElement, consumer, matcher); } else if (referenceElement instanceof GrReferenceExpressionImpl) { CompleteReferenceExpression.processVariants(matcher, consumer, (GrReferenceExpressionImpl)referenceElement, parameters); From 4b9bd26333dab8ac7161ec65e4fad0957122e796 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 3 Nov 2017 18:08:47 +0300 Subject: [PATCH 22/43] [groovy] completion for reference elements --- .../plugins/groovy/util/functions.kt | 8 + .../completion/completeReferenceElement.kt | 151 ++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/functions.kt create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/completeReferenceElement.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/functions.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/functions.kt new file mode 100644 index 000000000000..6c0380d192bf --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/functions.kt @@ -0,0 +1,8 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.util + +import com.intellij.util.Consumer + +fun Consumer.consumeAll(items: Iterable) { + items.forEach(this::consume) +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/completeReferenceElement.kt b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/completeReferenceElement.kt new file mode 100644 index 000000000000..92c7dfbf4141 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/completeReferenceElement.kt @@ -0,0 +1,151 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.completion + +import com.intellij.codeInsight.completion.JavaClassNameCompletionContributor +import com.intellij.codeInsight.completion.JavaClassNameCompletionContributor.createClassLookupItems +import com.intellij.codeInsight.completion.PrefixMatcher +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.openapi.util.Conditions +import com.intellij.openapi.util.Key +import com.intellij.psi.* +import com.intellij.psi.scope.BaseScopeProcessor +import com.intellij.psi.scope.ElementClassHint.DeclarationKind.CLASS +import com.intellij.psi.scope.ElementClassHint.DeclarationKind.PACKAGE +import com.intellij.psi.scope.PsiScopeProcessor +import com.intellij.util.Consumer +import org.jetbrains.plugins.groovy.lang.completion.GroovyCompletionUtil.setupLookupBuilder +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinitionBody +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeArgumentList +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameterList +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.skipWhitespacesAndComments +import org.jetbrains.plugins.groovy.lang.psi.util.treeWalkUp +import org.jetbrains.plugins.groovy.lang.resolve.imports.importedNameKey +import org.jetbrains.plugins.groovy.lang.resolve.processClasses +import org.jetbrains.plugins.groovy.lang.resolve.processors.GrDelegatingScopeProcessorWithHints +import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolveKind +import org.jetbrains.plugins.groovy.lang.resolve.processors.StaticMembersFilteringProcessor +import org.jetbrains.plugins.groovy.lang.resolve.qualifiedReferenceName +import org.jetbrains.plugins.groovy.lang.resolve.resolveClassFqn +import org.jetbrains.plugins.groovy.util.consumeAll + +private typealias LookupConsumer = Consumer + +fun GrCodeReferenceElement.complete(matcher: PrefixMatcher, consumer: LookupConsumer) { + val parent = parent + + val afterNew = JavaClassNameCompletionContributor.AFTER_NEW.accepts(this) + val processor = CompleteReferenceProcessor(matcher, consumer, afterNew) + + if (parent is GrImportStatement) { + if (parent.isStatic) processClassDeclarations(processor) + processPackageDeclarations(GrDelegatingScopeProcessorWithHints(processor, CLASS, PACKAGE)) + return + } + + val packageProcessor = GrDelegatingScopeProcessorWithHints(processor, PACKAGE) + if (parent is GrPackageDefinition) { + processPackageDeclarations(packageProcessor) + return + } + + processTypeParameters(processor) + + val classProcessor = GrDelegatingScopeProcessorWithHints(processor, CLASS) + processClasses(classProcessor, ResolveState.initial()) + if (qualifier != null) { + processPackageDeclarations(classProcessor) + } + processPackageDeclarations(packageProcessor) +} + +private fun GrCodeReferenceElement.processPackageDeclarations(processor: PsiScopeProcessor) { + val qualifier = qualifier + val qualifierFqn = if (qualifier == null) "" else qualifier.qualifiedReferenceName ?: return + val parentPackage = JavaPsiFacade.getInstance(project).findPackage(qualifierFqn) ?: return + parentPackage.processDeclarations(processor, ResolveState.initial(), null, this) +} + +private fun GrCodeReferenceElement.processClassDeclarations(processor: PsiScopeProcessor) { + val qualifier = qualifier ?: return + val clazz = qualifier.resolveClassFqn() ?: return + clazz.processDeclarations(StaticMembersFilteringProcessor(processor, null), ResolveState.initial(), null, this) +} + +private fun GrCodeReferenceElement.processTypeParameters(processor: PsiScopeProcessor) { + val typeParameterProcessor = object : GrDelegatingScopeProcessorWithHints(processor, emptySet()), GroovyResolveKind.Hint { + @Suppress("UNCHECKED_CAST") + override fun getHint(hintKey: Key): T? = if (hintKey === GroovyResolveKind.HINT_KEY) this as T else super.getHint(hintKey) + + override fun shouldProcess(kind: GroovyResolveKind): Boolean = kind === GroovyResolveKind.TYPE_PARAMETER + } + findTypeParameterListCandidate()?.processDeclarations(typeParameterProcessor, ResolveState.initial(), null, this) + treeWalkUp(typeParameterProcessor, ResolveState.initial()) +} + +private class CompleteReferenceProcessor( + private val matcher: PrefixMatcher, + private val consumer: LookupConsumer, + private val afterNew: Boolean +) : BaseScopeProcessor() { + + override fun execute(element: PsiElement, state: ResolveState): Boolean { + element as? PsiNamedElement ?: return true + + val name = element.name ?: return true + val importedName = state.get(importedNameKey) + + if (element is PsiClass && importedName != null && importedName != name) { + val builder = LookupElementBuilder.create(element, importedName).withPresentableText(importedName) + val item = setupLookupBuilder(element, state.get(PsiSubstitutor.KEY), builder, null) + consumer.consume(item) + } + else if (matcher.prefixMatches(name)) { + if (element is PsiClass) { + val items = createClassLookupItems(element, afterNew, GroovyClassNameInsertHandler(), Conditions.alwaysTrue()) + consumer.consumeAll(items) + } + else { + val builder = LookupElementBuilder.create(element, name) + val item = GroovyCompletionUtil.setupLookupBuilder(element, PsiSubstitutor.EMPTY, builder, null) + consumer.consume(item) + } + } + + return true + } +} + +private fun GrCodeReferenceElement.findTypeParameterListCandidate(): GrTypeParameterList? { + val typeElement = getRootTypeElement() ?: return null + val parent = typeElement.parent + return when (parent) { + is GrTypeDefinitionBody -> skipWhitespacesAndComments(typeElement.prevSibling, false) as? GrTypeParameterList + is GrVariableDeclaration -> { + val errorElement = skipWhitespacesAndComments(typeElement.prevSibling, false) as? PsiErrorElement + errorElement?.firstChild as? GrTypeParameterList + } + else -> null + } +} + +private fun GrCodeReferenceElement.getRootTypeElement(): GrTypeElement? { + var current: PsiElement? = parent + while (current.isTypeElementChild()) { + val parent = current?.parent + if (current is GrTypeElement) { + if (!parent.isTypeElementChild()) return current + } + current = parent + } + return null +} + +private fun PsiElement?.isTypeElementChild(): Boolean { + return this is GrCodeReferenceElement || this is GrTypeArgumentList || this is GrTypeElement +} From b868328b14f5c20b8b38265ec6924b577f2790ca Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 3 Nov 2017 19:00:16 +0300 Subject: [PATCH 23/43] [groovy] add GrCodeReferenceElement#getKind --- .../lang/psi/api/types/CodeReferenceKind.kt | 8 +++++ .../psi/api/types/GrCodeReferenceElement.java | 20 +++--------- .../groovy/lang/psi/impl/psiImplUtil.kt | 32 +++++++++---------- .../GrLightClassReferenceElement.java | 23 ++++--------- .../types/GrCodeReferenceElementImpl.java | 9 ++++++ .../lang/resolve/GrCodeReferenceResolver.kt | 18 +---------- 6 files changed, 46 insertions(+), 64 deletions(-) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/types/CodeReferenceKind.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/types/CodeReferenceKind.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/types/CodeReferenceKind.kt new file mode 100644 index 000000000000..84c442b6573b --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/types/CodeReferenceKind.kt @@ -0,0 +1,8 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.psi.api.types + +enum class CodeReferenceKind { + PACKAGE_REFERENCE, + IMPORT_REFERENCE, + REFERENCE +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/types/GrCodeReferenceElement.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/types/GrCodeReferenceElement.java index c37d27a5beb2..96ff93dbdd24 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/types/GrCodeReferenceElement.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/types/GrCodeReferenceElement.java @@ -1,21 +1,8 @@ -/* - * Copyright 2000-2014 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.psi.api.types; +import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; /** @@ -24,4 +11,7 @@ import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; */ public interface GrCodeReferenceElement extends GrReferenceElement { GrCodeReferenceElement[] EMPTY_ARRAY = new GrCodeReferenceElement[0]; + + @NotNull + CodeReferenceKind getKind(); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/psiImplUtil.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/psiImplUtil.kt index 52ed1d0f7a37..1b2b371acf84 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/psiImplUtil.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/psiImplUtil.kt @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.psi.impl import com.intellij.openapi.util.Key @@ -26,6 +12,10 @@ import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition +import org.jetbrains.plugins.groovy.lang.psi.api.types.CodeReferenceKind +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement internal fun GroovyFileImpl.getScriptDeclarations(topLevelOnly: Boolean): Array { val tree = stubTree ?: return collectScriptDeclarations(topLevelOnly) @@ -66,4 +56,14 @@ private fun GroovyFileImpl.doCollectScriptDeclarations(topLevelOnly: Boolean): A } }) return result.toTypedArray() -} \ No newline at end of file +} + +fun GrCodeReferenceElement.doGetKind(): CodeReferenceKind { + val parent = parent + return when (parent) { + is GrPackageDefinition -> CodeReferenceKind.PACKAGE_REFERENCE + is GrImportStatement -> CodeReferenceKind.IMPORT_REFERENCE + is GrCodeReferenceElement -> parent.getKind() + else -> CodeReferenceKind.REFERENCE + } +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightClassReferenceElement.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightClassReferenceElement.java index ec439115c683..cd8257d37423 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightClassReferenceElement.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightClassReferenceElement.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.psi.impl.synthetic; import com.intellij.openapi.util.TextRange; @@ -28,6 +14,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyLanguage; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.types.CodeReferenceKind; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeArgumentList; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; @@ -164,5 +151,9 @@ public class GrLightClassReferenceElement extends LightElement implements GrCode return myText; } - + @NotNull + @Override + public CodeReferenceKind getKind() { + return CodeReferenceKind.REFERENCE; + } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java index 130547452864..8d8de8913ac8 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java @@ -19,6 +19,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExp import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition; +import org.jetbrains.plugins.groovy.lang.psi.api.types.CodeReferenceKind; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeArgumentList; import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper; @@ -26,6 +27,8 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.GrReferenceElementImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.resolve.GrCodeReferencePolyVariantResolver; +import static org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtilKt.doGetKind; + /** * @author: Dmitry.Krasilschikov * @date: 26.03.2007 @@ -265,4 +268,10 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl } } -private enum class CodeReferenceKind { - PACKAGE_REFERENCE, - IMPORT_REFERENCE, - REFERENCE -} - -private fun GrCodeReferenceElement.getKind(): CodeReferenceKind { - val parent = parent - return when (parent) { - is GrPackageDefinition -> CodeReferenceKind.PACKAGE_REFERENCE - is GrImportStatement -> CodeReferenceKind.IMPORT_REFERENCE - is GrCodeReferenceElement -> parent.getKind() - else -> CodeReferenceKind.REFERENCE - } -} - private fun GrCodeReferenceElement.resolveAsPackageReference(): Collection { val fqn = qualifiedReferenceName ?: return emptyList() val pckg = JavaPsiFacade.getInstance(project).findPackage(fqn) ?: return emptyList() From 2863110ec47762ce7d9016ccce738fe261604e5a Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 3 Nov 2017 19:03:30 +0300 Subject: [PATCH 24/43] [groovy] cleanup --- .../groovy/lang/psi/impl/psiImplUtil.kt | 2 +- .../types/GrCodeReferenceElementImpl.java | 100 ++------ .../lang/resolve/GrCodeReferenceResolver.kt | 13 +- .../lang/resolve/processors/ClassHint.java | 17 +- .../processors/ClassResolverProcessor.java | 5 - .../processors/CompletionProcessor.java | 25 +- .../CompleteCodeReferenceElement.java | 219 ------------------ 7 files changed, 28 insertions(+), 353 deletions(-) delete mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/CompleteCodeReferenceElement.java diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/psiImplUtil.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/psiImplUtil.kt index 1b2b371acf84..298ad0a58167 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/psiImplUtil.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/psiImplUtil.kt @@ -63,7 +63,7 @@ fun GrCodeReferenceElement.doGetKind(): CodeReferenceKind { return when (parent) { is GrPackageDefinition -> CodeReferenceKind.PACKAGE_REFERENCE is GrImportStatement -> CodeReferenceKind.IMPORT_REFERENCE - is GrCodeReferenceElement -> parent.getKind() + is GrCodeReferenceElement -> parent.kind else -> CodeReferenceKind.REFERENCE } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java index 8d8de8913ac8..241c3216a581 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java @@ -9,16 +9,13 @@ import com.intellij.psi.*; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocReferenceElement; import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.types.CodeReferenceKind; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeArgumentList; @@ -28,6 +25,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.resolve.GrCodeReferencePolyVariantResolver; import static org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtilKt.doGetKind; +import static org.jetbrains.plugins.groovy.lang.resolve.ReferencesKt.getQualifiedReferenceName; /** * @author: Dmitry.Krasilschikov @@ -80,62 +78,14 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl { override fun resolve(ref: GrCodeReferenceElement, incomplete: Boolean): Collection { - val kind = ref.getKind() - @Suppress("UnnecessaryVariable") - val results = when (kind) { - CodeReferenceKind.PACKAGE_REFERENCE -> ref.resolveAsPackageReference() - CodeReferenceKind.IMPORT_REFERENCE -> ref.resolveAsImportReference() - CodeReferenceKind.REFERENCE -> ref.resolveReference() + return when (ref.kind) { + PACKAGE_REFERENCE -> ref.resolveAsPackageReference() + IMPORT_REFERENCE -> ref.resolveAsImportReference() + REFERENCE -> ref.resolveReference() } - return results } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ClassHint.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ClassHint.java index 55eb9429b63a..7af639d37505 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ClassHint.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ClassHint.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2015 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.resolve.processors; @@ -29,7 +15,6 @@ import static com.intellij.psi.scope.ElementClassHint.DeclarationKind.*; */ public interface ClassHint { Key RESOLVE_CONTEXT = Key.create("RESOLVE_CONTEXT"); - EnumSet RESOLVE_KINDS_CLASS_PACKAGE = EnumSet.of(CLASS, PACKAGE); EnumSet RESOLVE_KINDS_CLASS = EnumSet.of(CLASS); EnumSet RESOLVE_KINDS_METHOD = EnumSet.of(METHOD); EnumSet RESOLVE_KINDS_PROPERTY = EnumSet.of(VARIABLE, FIELD, ENUM_CONST); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ClassResolverProcessor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ClassResolverProcessor.java index df30e93deda0..3d97aa0b6ed6 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ClassResolverProcessor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ClassResolverProcessor.java @@ -3,7 +3,6 @@ package org.jetbrains.plugins.groovy.lang.resolve.processors; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; -import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; import static org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint.RESOLVE_KINDS_CLASS; @@ -11,10 +10,6 @@ import static org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint.RES * @author ven */ public class ClassResolverProcessor extends ResolverProcessorImpl { - public ClassResolverProcessor(String refName, GrReferenceElement ref) { - super(refName, RESOLVE_KINDS_CLASS, ref, ref.getTypeArguments()); - } - public ClassResolverProcessor(String refName, PsiElement place) { super(refName, RESOLVE_KINDS_CLASS, place, PsiType.EMPTY_ARRAY); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/CompletionProcessor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/CompletionProcessor.java index 65e6b65a235c..6ea8a55b578b 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/CompletionProcessor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/CompletionProcessor.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2015 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.resolve.processors; @@ -26,7 +12,6 @@ import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import java.util.EnumSet; -import static org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint.RESOLVE_KINDS_CLASS_PACKAGE; import static org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint.RESOLVE_KINDS_METHOD_PROPERTY; /** @@ -50,14 +35,6 @@ public class CompletionProcessor extends ResolverProcessorImpl { return new CompletionProcessor(place, RESOLVE_KINDS_METHOD_PROPERTY, null); } - public static ResolverProcessor createRefSameNameProcessor(PsiElement place, String name) { - return new CompletionProcessor(place, RESOLVE_KINDS_METHOD_PROPERTY, name); - } - - public static ResolverProcessor createClassCompletionProcessor(PsiElement place) { - return new CompletionProcessor(place, RESOLVE_KINDS_CLASS_PACKAGE, null); - } - @Override @NotNull public GroovyResolveResult[] getCandidates() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/CompleteCodeReferenceElement.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/CompleteCodeReferenceElement.java deleted file mode 100644 index a593bcf48444..000000000000 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/CompleteCodeReferenceElement.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright 2000-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.plugins.groovy.lang.completion; - -import com.intellij.codeInsight.completion.JavaClassNameCompletionContributor; -import com.intellij.codeInsight.completion.PrefixMatcher; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.util.Consumer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinitionBody; -import org.jetbrains.plugins.groovy.lang.psi.api.types.*; -import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; -import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrCodeReferenceElementImpl; -import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; -import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; -import org.jetbrains.plugins.groovy.lang.resolve.processors.CompletionProcessor; -import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor; - -import java.util.List; - -import static org.jetbrains.plugins.groovy.lang.psi.util.PsiTreeUtilKt.treeWalkUp; - -public class CompleteCodeReferenceElement { - private static final Logger LOG = Logger.getInstance(CompleteCodeReferenceElement.class); - - private final GrCodeReferenceElementImpl myRef; - private final Consumer myConsumer; - private final PrefixMatcher myMatcher; - - private CompleteCodeReferenceElement(@NotNull GrCodeReferenceElementImpl ref, - @NotNull Consumer consumer, - @NotNull PrefixMatcher matcher) { - myRef = ref; - myConsumer = consumer; - myMatcher = matcher; - } - - public static void processVariants(@NotNull GrCodeReferenceElementImpl ref, - @NotNull Consumer consumer, - @NotNull PrefixMatcher matcher) { - new CompleteCodeReferenceElement(ref, consumer, matcher).processVariantsImpl(); - } - - private void feedLookupElements(@NotNull PsiNamedElement psi, boolean afterNew) { - GroovyResolveResultImpl candidate = new GroovyResolveResultImpl(psi, true); - List elements = GroovyCompletionUtil.createLookupElements(candidate, afterNew, myMatcher, null); - for (LookupElement element : elements) { - myConsumer.consume(element); - } - } - - public void processVariantsImpl() { - boolean afterNew = JavaClassNameCompletionContributor.AFTER_NEW.accepts(myRef); - - switch (myRef.getKind(true)) { - case STATIC_MEMBER_FQ: { - final GrCodeReferenceElement qualifier = myRef.getQualifier(); - if (qualifier != null) { - final PsiElement resolve = qualifier.resolve(); - if (resolve instanceof PsiClass) { - final PsiClass clazz = (PsiClass)resolve; - - for (PsiField field : clazz.getFields()) { - if (field.hasModifierProperty(PsiModifier.STATIC)) { - feedLookupElements(field, afterNew); - } - } - - for (PsiMethod method : clazz.getMethods()) { - if (method.hasModifierProperty(PsiModifier.STATIC)) { - feedLookupElements(method, afterNew); - } - } - - for (PsiClass inner : clazz.getInnerClasses()) { - if (inner.hasModifierProperty(PsiModifier.STATIC)) { - feedLookupElements(inner, afterNew); - } - } - return; - } - } - } - // fall through - - case PACKAGE_FQ: - case CLASS_FQ: - case CLASS_OR_PACKAGE_FQ: { - final String refText = PsiUtil.getQualifiedReferenceText(myRef); - LOG.assertTrue(refText != null, myRef.getText()); - - String parentPackageFQName = StringUtil.getPackageName(refText); - final PsiPackage parentPackage = JavaPsiFacade.getInstance(myRef.getProject()).findPackage(parentPackageFQName); - if (parentPackage != null) { - final GlobalSearchScope scope = myRef.getResolveScope(); - if (myRef.getKind(true) == GrCodeReferenceElementImpl.ReferenceKind.PACKAGE_FQ) { - for (PsiPackage aPackage : parentPackage.getSubPackages(scope)) { - feedLookupElements(aPackage, afterNew); - } - return; - } - - if (myRef.getKind(true) == GrCodeReferenceElementImpl.ReferenceKind.CLASS_FQ) { - for (PsiClass aClass : parentPackage.getClasses(scope)) { - feedLookupElements(aClass, afterNew); - } - return; - } - - for (PsiPackage aPackage : parentPackage.getSubPackages(scope)) { - feedLookupElements(aPackage, afterNew); - } - for (PsiClass aClass : parentPackage.getClasses(scope)) { - feedLookupElements(aClass, afterNew); - } - return; - } - } - - case CLASS_OR_PACKAGE: - case CLASS: { - GrCodeReferenceElement qualifier = myRef.getQualifier(); - if (qualifier != null) { - PsiElement qualifierResolved = qualifier.resolve(); - if (qualifierResolved instanceof PsiPackage) { - PsiPackage aPackage = (PsiPackage)qualifierResolved; - for (PsiClass aClass : aPackage.getClasses(myRef.getResolveScope())) { - feedLookupElements(aClass, afterNew); - } - if (myRef.getKind(true) == GrCodeReferenceElementImpl.ReferenceKind.CLASS) return; - - for (PsiPackage subpackage : aPackage.getSubPackages(myRef.getResolveScope())) { - feedLookupElements(subpackage, afterNew); - } - } - else if (qualifierResolved instanceof PsiClass) { - for (PsiClass aClass : ((PsiClass)qualifierResolved).getInnerClasses()) { - feedLookupElements(aClass, afterNew); - } - } - } - else { - ResolverProcessor classProcessor = CompletionProcessor.createClassCompletionProcessor(myRef); - processTypeParametersFromUnfinishedMethodOrField(classProcessor); - - treeWalkUp(myRef, classProcessor); - - for (LookupElement o : GroovyCompletionUtil.getCompletionVariants(classProcessor.getCandidates(), afterNew, myMatcher, myRef)) { - myConsumer.consume(o); - } - } - } - } - } - - private void processTypeParametersFromUnfinishedMethodOrField(@NotNull ResolverProcessor processor) { - - final PsiElement candidate = findTypeParameterListCandidate(); - - if (candidate instanceof GrTypeParameterList) { - for (GrTypeParameter p : ((GrTypeParameterList)candidate).getTypeParameters()) { - ResolveUtil.processElement(processor, p, ResolveState.initial()); - } - } - } - - @Nullable - private PsiElement findTypeParameterListCandidate() { - final GrTypeElement typeElement = getRootTypeElement(); - if (typeElement == null) return null; - - if (typeElement.getParent() instanceof GrTypeDefinitionBody) { - return PsiUtil.skipWhitespacesAndComments(typeElement.getPrevSibling(), false); - } - - if (typeElement.getParent() instanceof GrVariableDeclaration) { - final PsiElement errorElement = PsiUtil.skipWhitespacesAndComments(typeElement.getPrevSibling(), false); - if (errorElement instanceof PsiErrorElement) { - return errorElement.getFirstChild(); - } - } - - return null; - } - - @Nullable - private GrTypeElement getRootTypeElement() { - PsiElement parent = myRef.getParent(); - while (isTypeElementChild(parent)) { - if (parent instanceof GrTypeElement && !isTypeElementChild(parent.getParent())) return (GrTypeElement)parent; - parent = parent.getParent(); - } - - return null; - } - - private static boolean isTypeElementChild(@Nullable PsiElement element) { - return element instanceof GrCodeReferenceElement || element instanceof GrTypeArgumentList || element instanceof GrTypeElement; - } -} From dbec3e848a67b0073f3cdbf1eb39e785f49e4b0c Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 3 Nov 2017 19:05:20 +0300 Subject: [PATCH 25/43] [groovy] set JvmName for completeReferenceElement.kt --- .../plugins/groovy/lang/completion/GroovyCompletionUtil.java | 3 +-- .../plugins/groovy/lang/completion/completeReferenceElement.kt | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java index bf123713cfdd..c703e8072ded 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java @@ -607,8 +607,7 @@ public class GroovyCompletionUtil { public static void processVariants(GrReferenceElement referenceElement, PrefixMatcher matcher, CompletionParameters parameters, Consumer consumer) { if (referenceElement instanceof GrCodeReferenceElementImpl) { - CompleteReferenceElementKt.complete((GrCodeReferenceElement)referenceElement, matcher, consumer); - //CompleteCodeReferenceElement.processVariants((GrCodeReferenceElementImpl)referenceElement, consumer, matcher); + CompleteCodeReferenceElement.complete((GrCodeReferenceElement)referenceElement, matcher, consumer); } else if (referenceElement instanceof GrReferenceExpressionImpl) { CompleteReferenceExpression.processVariants(matcher, consumer, (GrReferenceExpressionImpl)referenceElement, parameters); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/completeReferenceElement.kt b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/completeReferenceElement.kt index 92c7dfbf4141..d2b0050cf4a2 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/completeReferenceElement.kt +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/completeReferenceElement.kt @@ -1,4 +1,6 @@ // Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +@file:JvmName("CompleteCodeReferenceElement") + package org.jetbrains.plugins.groovy.lang.completion import com.intellij.codeInsight.completion.JavaClassNameCompletionContributor From 6646975f4490ac3824e3646b784535dce34e087b Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Tue, 14 Nov 2017 20:20:10 +0300 Subject: [PATCH 26/43] [groovy] file declarations processing order --- .../plugins/groovy/lang/psi/impl/GroovyFileImpl.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java index c106526124d7..f2c60ef76e7e 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java @@ -198,19 +198,19 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile, Ps } final GroovyFileImports imports = getImports(this); + + if (!processClassesInFile(this, processor, state)) return false; if (!processImports.fun(imports.getRegularImports())) return false; if (!processImports.fun(imports.getStaticImports())) return false; - if (!processClassesInFile(this, processor, state)) return false; - - if (ResolveUtil.shouldProcessProperties(classHint)) { - if (!processChildrenScopes(processor, state, lastParent, place)) return false; - } - if (!processClassesInPackage(this, processor, state, place)) return false; if (!processImports.fun(imports.getStarImports())) return false; if (!processImports.fun(imports.getStaticStarImports())) return false; if (!processImports.fun(getDefaultImports())) return false; + if (ResolveUtil.shouldProcessProperties(classHint)) { + if (!processChildrenScopes(processor, state, lastParent, place)) return false; + } + if (ResolveUtil.shouldProcessPackages(classHint)) { NameHint nameHint = processor.getHint(NameHint.KEY); From bcdf4c2f8fc87e00acb163e3f463f6666050ef72 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Wed, 15 Nov 2017 18:28:03 +0300 Subject: [PATCH 27/43] [groovy] add class resolution tests --- .../lang/resolve/ResolveClassInNewTest.groovy | 171 ++++++++++++++++++ .../lang/resolve/ResolveClassTest.groovy | 5 +- .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ .../anotherUnrelatedPackage/classes.groovy | 14 ++ .../src/somePackage/classes.groovy | 27 +++ .../src/somePackage/test.groovy | 71 ++++++++ .../src/unrelatedPackage/classes.groovy | 14 ++ 98 files changed, 3198 insertions(+), 2 deletions(-) create mode 100644 plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassInNewTest.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classInSameFile/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classInSameFile/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classInSameFile/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classInSameFile/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classInSamePackage/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classInSamePackage/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classInSamePackage/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classInSamePackage/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classRegularImport/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classRegularImport/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classRegularImport/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classRegularImport/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classRegularImport2/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classRegularImport2/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classRegularImport2/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classRegularImport2/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStarImport/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStarImport/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStarImport/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStarImport/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStarImport2/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStarImport2/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStarImport2/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStarImport2/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStaticImport/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStaticImport/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStaticImport/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStaticImport/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStaticImport2/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStaticImport2/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStaticImport2/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStaticImport2/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStaticStarImport/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStaticStarImport/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStaticStarImport/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStaticStarImport/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStaticStarImport2/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStaticStarImport2/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStaticStarImport2/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/classStaticStarImport2/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/doNotResolveOthers/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/doNotResolveOthers/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/doNotResolveOthers/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/doNotResolveOthers/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentClass/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentClass/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentClass/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentClass/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterface/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterface/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterface/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterface/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterfaceOutside/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterfaceOutside/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterfaceOutside/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterfaceOutside/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClass/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClass/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClass/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClass/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterface/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterface/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterface/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterface/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterfaceOutside/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterfaceOutside/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterfaceOutside/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterfaceOutside/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClass/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClass/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClass/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClass/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClassInterface/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClassInterface/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClassInterface/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClassInterface/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclass/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclass/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclass/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclass/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterface/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterface/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterface/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterface/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterfaceOutside/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterfaceOutside/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterfaceOutside/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterfaceOutside/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutside/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutside/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutside/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutside/src/unrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutsideInterface/src/anotherUnrelatedPackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutsideInterface/src/somePackage/classes.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutsideInterface/src/somePackage/test.groovy create mode 100644 plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutsideInterface/src/unrelatedPackage/classes.groovy diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassInNewTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassInNewTest.groovy new file mode 100644 index 000000000000..666db03ccb8e --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassInNewTest.groovy @@ -0,0 +1,171 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve + +import com.intellij.psi.PsiClass +import com.intellij.testFramework.LightProjectDescriptor +import groovy.transform.CompileStatic +import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.LightGroovyTestCase +import org.jetbrains.plugins.groovy.util.TestUtils + +@CompileStatic +class ResolveClassInNewTest extends LightGroovyTestCase { + + final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + + final String basePath = TestUtils.testDataPath + '/resolve/classInNew' + + private void doDirectoryTest(String fqn) { + final name = getTestName() + fixture.copyDirectoryToProject "$name/src", '/' + fixture.configureFromTempProjectFile "/somePackage/test.groovy" + final reference = file.findReferenceAt editor.caretModel.offset + final resolved = reference.resolve() + if (fqn == null) { + assertNull(resolved) + return + } + final clazz = assertInstanceOf(resolved, PsiClass) + + def currentClass = clazz + def parts = fqn.split('\\$') + def outerFqn = parts.head() + def inners = parts.tail().reverse() + for (part in inners) { + assertEquals(part, currentClass.name) + currentClass = currentClass.containingClass + } + assertNull(currentClass.containingClass) + assertEquals(outerFqn, currentClass.qualifiedName) + } + + // 1. current class & hierarchy with interfaces: + // class, all interfaces (including superinterfaces), superclass, all its interfaces, ... + + // Current + // CurrentI, CurrentIOutside + + // CurrentParent + // CurrentParentI, CurrentParentIOutside + // (https://issues.apache.org/jira/browse/GROOVY-8358) + + // CurrentParentOutside (https://issues.apache.org/jira/browse/GROOVY-8359) + // CurrentParentOutsideI + + // 2. outer classes from outermost to current with interfaces but no hierarchy + // OuterOuter + // OuterOuterI + + // Outer + // OuterI, OuterIOutside + + // 3. class in the same file + // 4. regular (aliased) imports by alias (inverse declaration order) + // 5. static (aliased) imports by alias (inverse declaration order) + // 6. class in the same package + // 7. static (aliased) imports by fieldName: in declaration order (https://issues.apache.org/jira/browse/GROOVY-8361) + // 8. star imports (declaration order) + // 9. static star imports (declaration order) + // 10. default imports + + void 'test inner class of current class'() { + doDirectoryTest 'somePackage.OuterOuter$Outer$Current$Target' + } + + void 'test inner class of current interface'() { + doDirectoryTest 'somePackage.CurrentI$Target' + } + + void 'test inner class of current interface outside'() { + doDirectoryTest 'somePackage.CurrentIOutside$Target' + } + + void 'test inner class of superclass'() { + doDirectoryTest 'somePackage.CurrentParent$Target' + } + + void 'test inner class of superclass interface'() { + doDirectoryTest 'somePackage.CurrentParentI$Target' + } + + void 'test inner class of superclass interface outside'() { + doDirectoryTest 'somePackage.CurrentParentIOutside$Target' + } + + // https://issues.apache.org/jira/browse/GROOVY-8359 + // Groovy fails to resolve such reference unless Target is in the same compilation unit + // We still resolve it + void 'test inner class of superclass outside'() { + doDirectoryTest 'somePackage.CurrentParentOutside$Target' + } + + void 'test inner class of superclass outside interface'() { + doDirectoryTest 'somePackage.CurrentParentOutsideI$Target' + } + + void 'test inner class of outermost class'() { + doDirectoryTest 'somePackage.OuterOuter$Target' + } + + void 'test inner class of outermost class interface'() { + doDirectoryTest 'somePackage.OuterOuterI$Target' + } + + void 'test inner class of outer class'() { + doDirectoryTest 'somePackage.OuterOuter$Outer$Target' + } + + void 'test inner class of outer class interface'() { + doDirectoryTest 'somePackage.OuterI$Target' + } + + void 'test inner class of outer class interface outside'() { + doDirectoryTest 'somePackage.OuterIOutside$Target' + } + + void 'test class in same file'() { + doDirectoryTest 'somePackage.Target' + } + + void 'test class regular import'() { + doDirectoryTest 'unrelatedPackage.Target' + } + + void 'test class regular import 2'() { + doDirectoryTest 'unrelatedPackage.Target2' + } + + void 'test class static import'() { + doDirectoryTest 'unrelatedPackage.Container$Target2' + } + + void 'test class static import 2'() { + doDirectoryTest 'unrelatedPackage.Container$Target' + } + + void 'test class in same package'() { + doDirectoryTest 'somePackage.Target' + } + + // this test also checks we don't resolve number 7 + // https://issues.apache.org/jira/browse/GROOVY-8361 + void 'test class star import'() { + doDirectoryTest 'anotherUnrelatedPackage.Target' + } + + void 'test class star import 2'() { + doDirectoryTest 'unrelatedPackage.Target' + } + + void 'test class static star import'() { + doDirectoryTest 'unrelatedPackage.Container$Target' + } + + void 'test class static star import 2'() { + doDirectoryTest 'unrelatedPackage.Container2$Target' + } + + void 'test do not resolve others'() { + doDirectoryTest null + } +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.groovy index f53256a4db8d..ffb8e1798a93 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.groovy @@ -593,7 +593,8 @@ new Bar() {} assert resolved.qualifiedName == 'foo.Foo' } - void 'test prefer alias over class in the same file'() { + // https://issues.apache.org/jira/browse/GROOVY-8254 + void 'test prefer class in the same file over alias'() { myFixture.addClass '''\ package foo; interface Foo {} @@ -607,7 +608,7 @@ new Bar() {} myFixture.configureFromExistingVirtualFile file.containingFile.virtualFile def resolved = myFixture.file.findReferenceAt(myFixture.editor.caretModel.offset).resolve() assert resolved instanceof PsiClass - assert resolved.qualifiedName == 'foo.Foo' + assert resolved.qualifiedName == 'test.Bar' } private void doTest(String fileName = getTestName(false) + ".groovy") { resolve(fileName, PsiClass) } diff --git a/plugins/groovy/testdata/resolve/classInNew/classInSameFile/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classInSameFile/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classInSameFile/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classInSameFile/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classInSameFile/src/somePackage/classes.groovy new file mode 100644 index 000000000000..60cc99f637fc --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classInSameFile/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { +// static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { +// static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classInSameFile/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/classInSameFile/src/somePackage/test.groovy new file mode 100644 index 000000000000..cde4d39a789c --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classInSameFile/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +import unrelatedPackage.Target2 as Target +import unrelatedPackage.Target + +import static unrelatedPackage.Container.Target +import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { +// static class Target {} +} + +interface OuterOuterI { +// static class Target {} +} + +class OuterOuter implements OuterOuterI { + +// static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + +// static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/classInSameFile/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classInSameFile/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classInSameFile/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classInSamePackage/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classInSamePackage/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classInSamePackage/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classInSamePackage/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classInSamePackage/src/somePackage/classes.groovy new file mode 100644 index 000000000000..60cc99f637fc --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classInSamePackage/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { +// static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { +// static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classInSamePackage/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/classInSamePackage/src/somePackage/test.groovy new file mode 100644 index 000000000000..28e8649e710a --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classInSamePackage/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +//import unrelatedPackage.Target2 as Target +//import unrelatedPackage.Target + +//import static unrelatedPackage.Container.Target +//import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +//class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { +// static class Target {} +} + +interface OuterOuterI { +// static class Target {} +} + +class OuterOuter implements OuterOuterI { + +// static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + +// static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/classInSamePackage/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classInSamePackage/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classInSamePackage/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classRegularImport/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classRegularImport/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classRegularImport/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classRegularImport/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classRegularImport/src/somePackage/classes.groovy new file mode 100644 index 000000000000..60cc99f637fc --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classRegularImport/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { +// static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { +// static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classRegularImport/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/classRegularImport/src/somePackage/test.groovy new file mode 100644 index 000000000000..31de81b9dbe0 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classRegularImport/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +import unrelatedPackage.Target2 as Target +import unrelatedPackage.Target + +import static unrelatedPackage.Container.Target +import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +//class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { +// static class Target {} +} + +interface OuterOuterI { +// static class Target {} +} + +class OuterOuter implements OuterOuterI { + +// static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + +// static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/classRegularImport/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classRegularImport/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classRegularImport/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classRegularImport2/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classRegularImport2/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classRegularImport2/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classRegularImport2/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classRegularImport2/src/somePackage/classes.groovy new file mode 100644 index 000000000000..60cc99f637fc --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classRegularImport2/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { +// static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { +// static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classRegularImport2/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/classRegularImport2/src/somePackage/test.groovy new file mode 100644 index 000000000000..2b1d51bb6de4 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classRegularImport2/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +import unrelatedPackage.Target2 as Target +//import unrelatedPackage.Target + +import static unrelatedPackage.Container.Target +import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +//class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { +// static class Target {} +} + +interface OuterOuterI { +// static class Target {} +} + +class OuterOuter implements OuterOuterI { + +// static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + +// static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/classRegularImport2/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classRegularImport2/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classRegularImport2/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStarImport/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classStarImport/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStarImport/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStarImport/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classStarImport/src/somePackage/classes.groovy new file mode 100644 index 000000000000..2da6da5b5380 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStarImport/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { +// static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { +// static class Target {} +} + +//class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStarImport/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/classStarImport/src/somePackage/test.groovy new file mode 100644 index 000000000000..28e8649e710a --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStarImport/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +//import unrelatedPackage.Target2 as Target +//import unrelatedPackage.Target + +//import static unrelatedPackage.Container.Target +//import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +//class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { +// static class Target {} +} + +interface OuterOuterI { +// static class Target {} +} + +class OuterOuter implements OuterOuterI { + +// static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + +// static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStarImport/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classStarImport/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStarImport/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStarImport2/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classStarImport2/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStarImport2/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStarImport2/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classStarImport2/src/somePackage/classes.groovy new file mode 100644 index 000000000000..2da6da5b5380 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStarImport2/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { +// static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { +// static class Target {} +} + +//class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStarImport2/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/classStarImport2/src/somePackage/test.groovy new file mode 100644 index 000000000000..e4255db079a4 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStarImport2/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +//import unrelatedPackage.Target2 as Target +//import unrelatedPackage.Target + +//import static unrelatedPackage.Container.Target +//import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +//import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +//class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { +// static class Target {} +} + +interface OuterOuterI { +// static class Target {} +} + +class OuterOuter implements OuterOuterI { + +// static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + +// static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStarImport2/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classStarImport2/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStarImport2/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStaticImport/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classStaticImport/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStaticImport/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStaticImport/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classStaticImport/src/somePackage/classes.groovy new file mode 100644 index 000000000000..60cc99f637fc --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStaticImport/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { +// static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { +// static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStaticImport/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/classStaticImport/src/somePackage/test.groovy new file mode 100644 index 000000000000..40074208197b --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStaticImport/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +//import unrelatedPackage.Target2 as Target +//import unrelatedPackage.Target + +import static unrelatedPackage.Container.Target +import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +//class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { +// static class Target {} +} + +interface OuterOuterI { +// static class Target {} +} + +class OuterOuter implements OuterOuterI { + +// static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + +// static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStaticImport/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classStaticImport/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStaticImport/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStaticImport2/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classStaticImport2/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStaticImport2/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStaticImport2/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classStaticImport2/src/somePackage/classes.groovy new file mode 100644 index 000000000000..60cc99f637fc --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStaticImport2/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { +// static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { +// static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStaticImport2/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/classStaticImport2/src/somePackage/test.groovy new file mode 100644 index 000000000000..3a019a50ed83 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStaticImport2/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +//import unrelatedPackage.Target2 as Target +//import unrelatedPackage.Target + +import static unrelatedPackage.Container.Target +//import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +//class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { +// static class Target {} +} + +interface OuterOuterI { +// static class Target {} +} + +class OuterOuter implements OuterOuterI { + +// static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + +// static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStaticImport2/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classStaticImport2/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStaticImport2/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport/src/somePackage/classes.groovy new file mode 100644 index 000000000000..2da6da5b5380 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { +// static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { +// static class Target {} +} + +//class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport/src/somePackage/test.groovy new file mode 100644 index 000000000000..df84ccfec486 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +//import unrelatedPackage.Target2 as Target +//import unrelatedPackage.Target + +//import static unrelatedPackage.Container.Target +//import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +//import anotherUnrelatedPackage.* +//import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +//class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { +// static class Target {} +} + +interface OuterOuterI { +// static class Target {} +} + +class OuterOuter implements OuterOuterI { + +// static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + +// static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport2/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport2/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport2/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport2/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport2/src/somePackage/classes.groovy new file mode 100644 index 000000000000..2da6da5b5380 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport2/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { +// static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { +// static class Target {} +} + +//class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport2/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport2/src/somePackage/test.groovy new file mode 100644 index 000000000000..e074c78acefb --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport2/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +//import unrelatedPackage.Target2 as Target +//import unrelatedPackage.Target + +//import static unrelatedPackage.Container.Target +//import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +//import anotherUnrelatedPackage.* +//import unrelatedPackage.* + +//import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +//class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { +// static class Target {} +} + +interface OuterOuterI { +// static class Target {} +} + +class OuterOuter implements OuterOuterI { + +// static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + +// static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport2/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport2/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/classStaticStarImport2/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/doNotResolveOthers/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/doNotResolveOthers/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/doNotResolveOthers/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/doNotResolveOthers/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/doNotResolveOthers/src/somePackage/classes.groovy new file mode 100644 index 000000000000..2da6da5b5380 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/doNotResolveOthers/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { +// static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { +// static class Target {} +} + +//class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/doNotResolveOthers/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/doNotResolveOthers/src/somePackage/test.groovy new file mode 100644 index 000000000000..c8953354a592 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/doNotResolveOthers/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +//import unrelatedPackage.Target2 as Target +//import unrelatedPackage.Target + +//import static unrelatedPackage.Container.Target +//import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +//import anotherUnrelatedPackage.* +//import unrelatedPackage.* + +//import static unrelatedPackage.Container.* +//import static unrelatedPackage.Container2.* + +//class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { +// static class Target {} +} + +interface OuterOuterI { +// static class Target {} +} + +class OuterOuter implements OuterOuterI { + +// static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + +// static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/doNotResolveOthers/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/doNotResolveOthers/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/doNotResolveOthers/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentClass/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentClass/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentClass/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentClass/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentClass/src/somePackage/classes.groovy new file mode 100644 index 000000000000..d2f929796f37 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentClass/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { + static class Target {} +} + +interface CurrentParentOutsideI { + static class Target {} +} + +interface CurrentIOutside { + static class Target {} +} + +interface CurrentParentIOutside { + static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { + static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentClass/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentClass/src/somePackage/test.groovy new file mode 100644 index 000000000000..89278ece18f2 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentClass/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +import unrelatedPackage.Target2 as Target +import unrelatedPackage.Target + +import static unrelatedPackage.Container.Target +import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +class Target {} + +interface CurrentI { + static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { + static class Target {} +} + +interface CurrentParentI { + static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { + static class Target {} +} + +interface OuterOuterI { + static class Target {} +} + +class OuterOuter implements OuterOuterI { + + static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + + static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + + static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentClass/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentClass/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentClass/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterface/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterface/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterface/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterface/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterface/src/somePackage/classes.groovy new file mode 100644 index 000000000000..d2f929796f37 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterface/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { + static class Target {} +} + +interface CurrentParentOutsideI { + static class Target {} +} + +interface CurrentIOutside { + static class Target {} +} + +interface CurrentParentIOutside { + static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { + static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterface/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterface/src/somePackage/test.groovy new file mode 100644 index 000000000000..d43fd6f152c7 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterface/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +import unrelatedPackage.Target2 as Target +import unrelatedPackage.Target + +import static unrelatedPackage.Container.Target +import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +class Target {} + +interface CurrentI { + static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { + static class Target {} +} + +interface CurrentParentI { + static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { + static class Target {} +} + +interface OuterOuterI { + static class Target {} +} + +class OuterOuter implements OuterOuterI { + + static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + + static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterface/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterface/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterface/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterfaceOutside/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterfaceOutside/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterfaceOutside/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterfaceOutside/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterfaceOutside/src/somePackage/classes.groovy new file mode 100644 index 000000000000..d2f929796f37 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterfaceOutside/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { + static class Target {} +} + +interface CurrentParentOutsideI { + static class Target {} +} + +interface CurrentIOutside { + static class Target {} +} + +interface CurrentParentIOutside { + static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { + static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterfaceOutside/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterfaceOutside/src/somePackage/test.groovy new file mode 100644 index 000000000000..54a47464e457 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterfaceOutside/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +import unrelatedPackage.Target2 as Target +import unrelatedPackage.Target + +import static unrelatedPackage.Container.Target +import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { + static class Target {} +} + +interface CurrentParentI { + static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { + static class Target {} +} + +interface OuterOuterI { + static class Target {} +} + +class OuterOuter implements OuterOuterI { + + static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + + static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterfaceOutside/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterfaceOutside/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfCurrentInterfaceOutside/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClass/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClass/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClass/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClass/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClass/src/somePackage/classes.groovy new file mode 100644 index 000000000000..10c761d44c9f --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClass/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { +// static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { + static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClass/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClass/src/somePackage/test.groovy new file mode 100644 index 000000000000..8cd701f659e2 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClass/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +import unrelatedPackage.Target2 as Target +import unrelatedPackage.Target + +import static unrelatedPackage.Container.Target +import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { + static class Target {} +} + +interface OuterOuterI { +// static class Target {} +} + +class OuterOuter implements OuterOuterI { + +// static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + + static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClass/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClass/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClass/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterface/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterface/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterface/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterface/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterface/src/somePackage/classes.groovy new file mode 100644 index 000000000000..10c761d44c9f --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterface/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { +// static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { + static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterface/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterface/src/somePackage/test.groovy new file mode 100644 index 000000000000..3617abd67fea --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterface/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +import unrelatedPackage.Target2 as Target +import unrelatedPackage.Target + +import static unrelatedPackage.Container.Target +import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { + static class Target {} +} + +interface OuterOuterI { +// static class Target {} +} + +class OuterOuter implements OuterOuterI { + +// static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + +// static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterface/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterface/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterface/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterfaceOutside/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterfaceOutside/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterfaceOutside/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterfaceOutside/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterfaceOutside/src/somePackage/classes.groovy new file mode 100644 index 000000000000..10c761d44c9f --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterfaceOutside/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { +// static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { + static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterfaceOutside/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterfaceOutside/src/somePackage/test.groovy new file mode 100644 index 000000000000..cde4d39a789c --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterfaceOutside/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +import unrelatedPackage.Target2 as Target +import unrelatedPackage.Target + +import static unrelatedPackage.Container.Target +import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { +// static class Target {} +} + +interface OuterOuterI { +// static class Target {} +} + +class OuterOuter implements OuterOuterI { + +// static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + +// static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterfaceOutside/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterfaceOutside/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOuterClassInterfaceOutside/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClass/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClass/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClass/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClass/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClass/src/somePackage/classes.groovy new file mode 100644 index 000000000000..10c761d44c9f --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClass/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { +// static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { + static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClass/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClass/src/somePackage/test.groovy new file mode 100644 index 000000000000..2b96ffed423e --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClass/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +import unrelatedPackage.Target2 as Target +import unrelatedPackage.Target + +import static unrelatedPackage.Container.Target +import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { + static class Target {} +} + +interface OuterOuterI { + static class Target {} +} + +class OuterOuter implements OuterOuterI { + + static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + + static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClass/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClass/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClass/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClassInterface/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClassInterface/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClassInterface/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClassInterface/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClassInterface/src/somePackage/classes.groovy new file mode 100644 index 000000000000..10c761d44c9f --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClassInterface/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { +// static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { + static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClassInterface/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClassInterface/src/somePackage/test.groovy new file mode 100644 index 000000000000..e56ab70296fe --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClassInterface/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +import unrelatedPackage.Target2 as Target +import unrelatedPackage.Target + +import static unrelatedPackage.Container.Target +import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { + static class Target {} +} + +interface OuterOuterI { + static class Target {} +} + +class OuterOuter implements OuterOuterI { + +// static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + + static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClassInterface/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClassInterface/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfOutermostClassInterface/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclass/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclass/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclass/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclass/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclass/src/somePackage/classes.groovy new file mode 100644 index 000000000000..a4f734e1ae2d --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclass/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { + static class Target {} +} + +interface CurrentParentOutsideI { + static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { + static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { + static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclass/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclass/src/somePackage/test.groovy new file mode 100644 index 000000000000..54a47464e457 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclass/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +import unrelatedPackage.Target2 as Target +import unrelatedPackage.Target + +import static unrelatedPackage.Container.Target +import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { + static class Target {} +} + +interface CurrentParentI { + static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { + static class Target {} +} + +interface OuterOuterI { + static class Target {} +} + +class OuterOuter implements OuterOuterI { + + static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + + static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclass/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclass/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclass/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterface/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterface/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterface/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterface/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterface/src/somePackage/classes.groovy new file mode 100644 index 000000000000..a4f734e1ae2d --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterface/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { + static class Target {} +} + +interface CurrentParentOutsideI { + static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { + static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { + static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterface/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterface/src/somePackage/test.groovy new file mode 100644 index 000000000000..de911a2a4a7d --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterface/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +import unrelatedPackage.Target2 as Target +import unrelatedPackage.Target + +import static unrelatedPackage.Container.Target +import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { + static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { + static class Target {} +} + +interface OuterOuterI { + static class Target {} +} + +class OuterOuter implements OuterOuterI { + + static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + + static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterface/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterface/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterface/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterfaceOutside/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterfaceOutside/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterfaceOutside/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterfaceOutside/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterfaceOutside/src/somePackage/classes.groovy new file mode 100644 index 000000000000..a4f734e1ae2d --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterfaceOutside/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { + static class Target {} +} + +interface CurrentParentOutsideI { + static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { + static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { + static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterfaceOutside/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterfaceOutside/src/somePackage/test.groovy new file mode 100644 index 000000000000..2b96ffed423e --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterfaceOutside/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +import unrelatedPackage.Target2 as Target +import unrelatedPackage.Target + +import static unrelatedPackage.Container.Target +import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { + static class Target {} +} + +interface OuterOuterI { + static class Target {} +} + +class OuterOuter implements OuterOuterI { + + static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + + static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterfaceOutside/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterfaceOutside/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassInterfaceOutside/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutside/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutside/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutside/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutside/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutside/src/somePackage/classes.groovy new file mode 100644 index 000000000000..86dd3c298baf --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutside/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { + static class Target {} +} + +interface CurrentParentOutsideI { + static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { +// static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { + static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutside/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutside/src/somePackage/test.groovy new file mode 100644 index 000000000000..2b96ffed423e --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutside/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +import unrelatedPackage.Target2 as Target +import unrelatedPackage.Target + +import static unrelatedPackage.Container.Target +import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { + static class Target {} +} + +interface OuterOuterI { + static class Target {} +} + +class OuterOuter implements OuterOuterI { + + static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + + static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutside/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutside/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutside/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutsideInterface/src/anotherUnrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutsideInterface/src/anotherUnrelatedPackage/classes.groovy new file mode 100644 index 000000000000..cfab1aeea9da --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutsideInterface/src/anotherUnrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package anotherUnrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutsideInterface/src/somePackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutsideInterface/src/somePackage/classes.groovy new file mode 100644 index 000000000000..27100b023fe2 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutsideInterface/src/somePackage/classes.groovy @@ -0,0 +1,27 @@ +package somePackage + +class CurrentParentOutside implements CurrentParentOutsideI { +// static class Target {} +} + +interface CurrentParentOutsideI { + static class Target {} +} + +interface CurrentIOutside { +// static class Target {} +} + +interface CurrentParentIOutside { +// static class Target {} +} + +class OuterParentOutside { + static class Target {} +} + +interface OuterIOutside { + static class Target {} +} + +class Target {} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutsideInterface/src/somePackage/test.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutsideInterface/src/somePackage/test.groovy new file mode 100644 index 000000000000..2b96ffed423e --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutsideInterface/src/somePackage/test.groovy @@ -0,0 +1,71 @@ +package somePackage + +import unrelatedPackage.Target2 as Target +import unrelatedPackage.Target + +import static unrelatedPackage.Container.Target +import static unrelatedPackage.Container.Target2 as Target + +import static unrelatedPackage.Container2.Target as Unrelated2 +import static unrelatedPackage.Container.Target as Unrelated + +import anotherUnrelatedPackage.* +import unrelatedPackage.* + +import static unrelatedPackage.Container.* +import static unrelatedPackage.Container2.* + +class Target {} + +interface CurrentI { +// static class Target {} +} + +class CurrentParent extends CurrentParentOutside implements CurrentParentI, CurrentParentIOutside { +// static class Target {} +} + +interface CurrentParentI { +// static class Target {} +} + +class OuterParent extends OuterParentOutside { + static class Target {} +} + +interface OuterI { + static class Target {} +} + +interface OuterOuterI { + static class Target {} +} + +class OuterOuter implements OuterOuterI { + + static class Target {} + + static class Outer extends OuterParent implements OuterI, OuterIOutside { + + static class Target {} + + static class Current extends CurrentParent implements CurrentI, CurrentIOutside { + +// static class Target {} + + static class Inner { + static class Target {} + } + + static usage() { + new Target() + } + } + } +} + +class Main { + static void main(String[] args) { + println OuterOuter.Outer.Current.usage() + } +} diff --git a/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutsideInterface/src/unrelatedPackage/classes.groovy b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutsideInterface/src/unrelatedPackage/classes.groovy new file mode 100644 index 000000000000..a0423d694523 --- /dev/null +++ b/plugins/groovy/testdata/resolve/classInNew/innerClassOfSuperclassOutsideInterface/src/unrelatedPackage/classes.groovy @@ -0,0 +1,14 @@ +package unrelatedPackage + +class Container { + static class Target {} + static class Target2 {} +} + +class Container2 { + static class Target {} + static class Target2 {} +} + +class Target {} +class Target2 {} From 5f99b816804c15e97cd5dc73ba101e742f2f419d Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Thu, 16 Nov 2017 02:29:52 +0300 Subject: [PATCH 28/43] [util] add Map.reverse() --- .../src/com/intellij/util/collections.kt | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/java/java-impl/src/com/intellij/util/collections.kt b/java/java-impl/src/com/intellij/util/collections.kt index 800a3936ba34..ebf0c34a34d3 100644 --- a/java/java-impl/src/com/intellij/util/collections.kt +++ b/java/java-impl/src/com/intellij/util/collections.kt @@ -1,18 +1,4 @@ -/* - * Copyright 2000-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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.util typealias LookbackValue = Pair @@ -41,3 +27,5 @@ private class LookbackIterator(private val iterator: Iterator) : Iterator< return result } } + +fun Map.reverse(): Map = map { (k, v) -> v to k }.toMap() From fdd8945fe9c1b58a70600b438746ec5ee376ff5c Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Thu, 16 Nov 2017 02:30:20 +0300 Subject: [PATCH 29/43] [groovy] make star import strategy query star import property --- .../plugins/groovy/lang/resolve/imports/impl/strategies.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/strategies.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/strategies.kt index 98bf02b48e23..79a0bd7d69f1 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/strategies.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/strategies.kt @@ -2,7 +2,6 @@ package org.jetbrains.plugins.groovy.lang.resolve.imports.impl import gnu.trove.TObjectHashingStrategy - import org.jetbrains.plugins.groovy.lang.resolve.imports.RegularImport import org.jetbrains.plugins.groovy.lang.resolve.imports.StarImport @@ -22,8 +21,8 @@ internal object StarImportHashingStrategy : TObjectHashingStrategy { override fun equals(o1: StarImport?, o2: StarImport?): Boolean { if (o1 === o2) return true if (o1 == null || o2 == null) return false - return o1.fqn == o2.fqn + return o1.packageFqn == o2.packageFqn } - override fun computeHashCode(o: StarImport?): Int = o?.fqn?.hashCode() ?: 0 + override fun computeHashCode(o: StarImport?): Int = o?.packageFqn?.hashCode() ?: 0 } From 7d5501dcab3a6418ba2b9230f86fe3c5f6463e50 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Thu, 16 Nov 2017 02:34:17 +0300 Subject: [PATCH 30/43] [groovy] update imports - make imports data classes; - don't store statement inside import; - process imports via GroovyFileImports instance; - extract collector logic into GroovyImportCollector; - move necessity check into imports; - move unnecessary import search into GroovyFileImports; - move unresolved import search into GroovyFileImports; - try to minimally expose internal how GroovyFileImports stores imports. --- .../groovy/lang/psi/impl/GroovyFileImpl.java | 27 ++-- .../lang/psi/impl/utils/psiImportUtil.kt | 13 +- .../lang/resolve/imports/GroovyFileImports.kt | 27 +++- .../lang/resolve/imports/GroovyImport.kt | 14 +- .../lang/resolve/imports/RegularImport.kt | 44 ++++-- .../groovy/lang/resolve/imports/StarImport.kt | 13 +- .../lang/resolve/imports/StaticImport.kt | 18 +-- .../lang/resolve/imports/StaticStarImport.kt | 14 +- .../imports/impl/GroovyFileImportsImpl.kt | 95 ++++++++++-- .../imports/impl/GroovyImportCollector.kt | 70 +++++++++ .../lang/resolve/imports/impl/ImportKind.kt | 12 ++ .../groovy/lang/resolve/imports/impl/impl.kt | 65 --------- .../groovy/lang/resolve/imports/imports.kt | 31 +++- .../lang/resolve/imports/unusedImports.kt | 136 +----------------- 14 files changed, 286 insertions(+), 293 deletions(-) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyImportCollector.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/ImportKind.kt delete mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/impl.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java index f2c60ef76e7e..4bdfe661a096 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java @@ -14,7 +14,6 @@ import com.intellij.psi.scope.NameHint; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.stubs.StubElement; import com.intellij.psi.util.*; -import com.intellij.util.BooleanFunction; import com.intellij.util.IncorrectOperationException; import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; @@ -44,7 +43,7 @@ import org.jetbrains.plugins.groovy.lang.psi.stubs.GrPackageDefinitionStub; import org.jetbrains.plugins.groovy.lang.resolve.MethodTypeInferencer; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyFileImports; -import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImport; +import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImports; import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint; import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolverProcessor; @@ -52,8 +51,6 @@ import java.util.concurrent.ConcurrentMap; import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.processClassesInFile; import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.processClassesInPackage; -import static org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImports.getDefaultImports; -import static org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImports.getImports; /** * Implements all abstractions related to Groovy file @@ -185,27 +182,17 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile, Ps return true; } - final BooleanFunction> processImports = imports -> { - for (GroovyImport anImport : imports) { - if (!anImport.processDeclarations(processor, state, place, this)) return false; - } - return true; - }; - final GroovyScriptClass scriptClass = getScriptClass(); if (scriptClass != null && !(lastParent instanceof GrTypeDefinition)) { if (!ResolveUtil.processClassDeclarations(scriptClass, processor, state, lastParent, place)) return false; } - final GroovyFileImports imports = getImports(this); - + final GroovyFileImports imports = getImports(); if (!processClassesInFile(this, processor, state)) return false; - if (!processImports.fun(imports.getRegularImports())) return false; - if (!processImports.fun(imports.getStaticImports())) return false; + if (!imports.processAllNamedImports(processor, state, place)) return false; if (!processClassesInPackage(this, processor, state, place)) return false; - if (!processImports.fun(imports.getStarImports())) return false; - if (!processImports.fun(imports.getStaticStarImports())) return false; - if (!processImports.fun(getDefaultImports())) return false; + if (!imports.processAllStarImports(processor, state, place)) return false; + if (!imports.processDefaultImports(processor, state, place)) return false; if (ResolveUtil.shouldProcessProperties(classHint)) { if (!processChildrenScopes(processor, state, lastParent, place)) return false; @@ -514,6 +501,10 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile, Ps return !isScript() || PsiTreeUtil.getParentOfType(place, GrTypeDefinition.class, GrVariableDeclaration.class) != null; } + protected GroovyFileImports getImports() { + return GroovyImports.getImports(this); + } + @Override public String toString() { if (ApplicationManager.getApplication().isUnitTestMode()) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/utils/psiImportUtil.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/utils/psiImportUtil.kt index 304dea4d9ea8..91e4aee29276 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/utils/psiImportUtil.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/utils/psiImportUtil.kt @@ -12,10 +12,7 @@ internal fun GrImportStatement.createImportFromStatement(): GroovyImport? { val static = isStatic val star = isOnDemand return if (static && star) { - StaticStarImport( - this, - classFqn = reference.qualifiedReferenceName ?: return null - ) + StaticStarImport(classFqn = reference.qualifiedReferenceName ?: return null) } else if (static) { val qualifier = reference.qualifier @@ -23,14 +20,12 @@ internal fun GrImportStatement.createImportFromStatement(): GroovyImport? { val importedName = importedName ?: return null if (qualifier == null) { RegularImport( - this, classFqn = name, name = importedName ) } else { StaticImport( - this, classFqn = qualifier.qualifiedReferenceName ?: return null, memberName = name, name = importedName @@ -38,14 +33,10 @@ internal fun GrImportStatement.createImportFromStatement(): GroovyImport? { } } else if (star) { - StarImport( - this, - packageFqn = reference.qualifiedReferenceName ?: return null - ) + StarImport(packageFqn = reference.qualifiedReferenceName ?: return null) } else { RegularImport( - this, classFqn = reference.qualifiedReferenceName ?: return null, name = importedName ?: return null ) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyFileImports.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyFileImports.kt index 6d0e4f0455f5..d9b4461dcf14 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyFileImports.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyFileImports.kt @@ -1,20 +1,33 @@ // Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.resolve.imports +import com.intellij.psi.PsiElement +import com.intellij.psi.ResolveState +import com.intellij.psi.scope.PsiScopeProcessor +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement + interface GroovyFileImports { - val regularImports: Collection - - val staticImports: Collection + val file: GroovyFile val starImports: Collection val staticStarImports: Collection - - val allImports: Collection - val allNamedImports: Collection - val allStarImports: Collection + + fun processStaticImports(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean + + fun processAllNamedImports(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean + + fun processAllStarImports(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean + + fun processDefaultImports(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean + + + fun findUnneecessaryStatements(): Collection + + fun findUnresolvedStatements(names: Collection): Collection } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyImport.kt index 18514813c5f3..b806d3d8f5fd 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyImport.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyImport.kt @@ -5,24 +5,24 @@ import com.intellij.psi.PsiElement import com.intellij.psi.ResolveState import com.intellij.psi.scope.PsiScopeProcessor import org.jetbrains.plugins.groovy.lang.psi.GroovyFile -import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement interface GroovyImport { - /** - * Returns statement from which this import was created or `null` - */ - val statement: GrImportStatement? - /** * Resolves current import using [file] as a context */ fun resolve(file: GroovyFile): PsiElement? /** - * Feeds the processor elements available via this import + * Feeds the processor with elements available via this import */ fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFile): Boolean + + /** + * Checks whether this import could be removed wihout any changes in resolve. + * Example: import com.foo.Bar is unnecessary when import com.foo.* is present + */ + fun isUnnecessary(imports: GroovyFileImports): Boolean } interface GroovyNamedImport : GroovyImport { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt index abfb4fd67dbd..ce0d005eb40e 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt @@ -1,6 +1,7 @@ // Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.resolve.imports +import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.util.text.StringUtil.getShortName import com.intellij.psi.JavaPsiFacade import com.intellij.psi.PsiClass @@ -8,9 +9,10 @@ import com.intellij.psi.PsiElement import com.intellij.psi.ResolveState import com.intellij.psi.scope.PsiScopeProcessor import org.jetbrains.plugins.groovy.lang.psi.GroovyFile -import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement import org.jetbrains.plugins.groovy.lang.resolve.checkName -import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint +import org.jetbrains.plugins.groovy.lang.resolve.processClassesInFile +import org.jetbrains.plugins.groovy.lang.resolve.processClassesInPackage +import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassProcessor import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessClasses /** @@ -26,14 +28,9 @@ import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessClasses * - [name] = `Bar` * - [isAliased] = `false` */ -class RegularImport internal constructor( - override val statement: GrImportStatement?, - val classFqn: String, - override val name: String -) : GroovyNamedImport { +data class RegularImport(val classFqn: String, override val name: String) : GroovyNamedImport { - constructor(fqn: String) : this(null, fqn, getShortName(fqn)) - constructor(fqn: String, name: String) : this(null, fqn, name) + constructor(classFqn: String) : this(classFqn, StringUtil.getShortName(classFqn)) override val isAliased: Boolean = getShortName(classFqn) != name @@ -48,7 +45,34 @@ class RegularImport internal constructor( if (!processor.checkName(name, state)) return true val clazz = resolve(file) ?: return true - return processor.execute(clazz, state.put(ClassHint.RESOLVE_CONTEXT, statement).put(importedNameKey, name)) + return processor.execute(clazz, state.put(importedNameKey, name)) + } + + override fun isUnnecessary(imports: GroovyFileImports): Boolean { + if (isAliased) return false + val file = imports.file + + val processor = ClassProcessor(name, file) + val state = ResolveState.initial() + + if (!imports.processStaticImports(processor, state, file)) return false + + val starImport = StarImport(StringUtil.getPackageName(classFqn)) + if (starImport.packageFqn == file.packageName) return true + + if (!file.processClassesInFile(processor, state)) return false + if (!file.processClassesInPackage(processor, state)) return false + + if (starImport in imports.starImports) return true + + if (!imports.processAllStarImports(processor, state, file)) return false + + val results = processor.results + assert(results.isEmpty()) { + "Processor returned true, but there are ${results.size} results: $results" + } + + return this in defaultRegularImportsSet || starImport in defaultStarImportsSet } override fun toString(): String = "import $classFqn as $name" diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StarImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StarImport.kt index ca5fcf6419ba..56df8678383f 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StarImport.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StarImport.kt @@ -7,15 +7,8 @@ import com.intellij.psi.PsiPackage import com.intellij.psi.ResolveState import com.intellij.psi.scope.PsiScopeProcessor import org.jetbrains.plugins.groovy.lang.psi.GroovyFile -import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement -import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint -class StarImport internal constructor( - override val statement: GrImportStatement?, - val packageFqn: String -) : GroovyStarImport { - - constructor(packageFqn: String) : this(null, packageFqn) +data class StarImport(val packageFqn: String) : GroovyStarImport { override val fqn: String get() = packageFqn @@ -26,8 +19,10 @@ class StarImport internal constructor( override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFile): Boolean { val pckg = resolve(file) ?: return true - return pckg.processDeclarations(processor, state.put(ClassHint.RESOLVE_CONTEXT, statement), null, place) + return pckg.processDeclarations(processor, state, null, place) } + override fun isUnnecessary(imports: GroovyFileImports): Boolean = this in defaultStarImportsSet + override fun toString(): String = "import $packageFqn.*" } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt index 7648d7c53be7..8eeb22a44b30 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt @@ -5,11 +5,9 @@ import com.intellij.psi.PsiElement import com.intellij.psi.ResolveState import com.intellij.psi.scope.PsiScopeProcessor import org.jetbrains.plugins.groovy.lang.psi.GroovyFile -import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils.* import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.NonFqnImport -import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolverProcessor import org.jetbrains.plugins.groovy.lang.resolve.processors.StaticMembersFilteringProcessor import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessMembers @@ -29,34 +27,36 @@ import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessMembers * - [name] = `Bar` * - [isAliased] = `false` */ -class StaticImport internal constructor( - override val statement: GrImportStatement?, +data class StaticImport constructor( override val classFqn: String, val memberName: String, - override val name: String = memberName + override val name: String ) : NonFqnImport(), GroovyNamedImport { - constructor(classFqn: String, memberName: String) : this(null, classFqn, memberName) - constructor(classFqn: String, memberName: String, name: String) : this(null, classFqn, memberName, name) + constructor(classFqn: String, memberName: String) : this(classFqn, memberName, memberName) override val isAliased: Boolean = memberName != name override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFile): Boolean { if (!processor.shouldProcessMembers()) return true val clazz = resolve(file) ?: return true - val stateWithContext = state.put(ClassHint.RESOLVE_CONTEXT, statement) val namesMapping = namesMapping() for (each in GroovyResolverProcessor.allProcessors(processor)) { val hintName = ResolveUtil.getNameHint(each) for ((memberName, alias) in namesMapping) { if (hintName != null && hintName != alias) continue val delegate = StaticMembersFilteringProcessor(each, memberName) - if (!clazz.processDeclarations(delegate, stateWithContext.put(importedNameKey, alias), null, place)) return false + if (!clazz.processDeclarations(delegate, state.put(importedNameKey, alias), null, place)) return false } } return true } + override fun isUnnecessary(imports: GroovyFileImports): Boolean { + if (isAliased) return false + return StaticStarImport(classFqn) in imports.staticStarImports + } + override fun toString(): String = "import static $classFqn.$memberName as $name" private fun namesMapping() = namesMapping(memberName, name) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticStarImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticStarImport.kt index 481ea7e720b7..b03e81aaf1a2 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticStarImport.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticStarImport.kt @@ -7,30 +7,24 @@ import com.intellij.psi.PsiElement import com.intellij.psi.ResolveState import com.intellij.psi.scope.PsiScopeProcessor import org.jetbrains.plugins.groovy.lang.psi.GroovyFile -import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.NonFqnImport -import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolverProcessor import org.jetbrains.plugins.groovy.lang.resolve.processors.StaticMembersFilteringProcessor -class StaticStarImport internal constructor( - override val statement: GrImportStatement?, - override val classFqn: String -) : NonFqnImport(), GroovyStarImport { - - constructor(classFqn: String) : this(null, classFqn) +data class StaticStarImport(override val classFqn: String) : NonFqnImport(), GroovyStarImport { override val fqn: String get() = classFqn override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFile): Boolean { val clazz = resolve(file) ?: return true - val stateWithContext = state.put(ClassHint.RESOLVE_CONTEXT, statement) for (each in GroovyResolverProcessor.allProcessors(processor)) { val filteringProcessor = StaticMembersFilteringProcessor(each, null) - if (!clazz.processDeclarations(filteringProcessor, stateWithContext, null, place)) return false + if (!clazz.processDeclarations(filteringProcessor, state, null, place)) return false } return true } + override fun isUnnecessary(imports: GroovyFileImports): Boolean = false + override fun toString(): String = "import static $classFqn.*" } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyFileImportsImpl.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyFileImportsImpl.kt index a16acdeb72f0..74b5691a7600 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyFileImportsImpl.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyFileImportsImpl.kt @@ -1,22 +1,97 @@ // Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +@file:Suppress("UseExpressionBody") + package org.jetbrains.plugins.groovy.lang.resolve.imports.impl -import org.jetbrains.plugins.groovy.lang.resolve.imports.* +import com.intellij.psi.PsiElement +import com.intellij.psi.ResolveState +import com.intellij.psi.scope.PsiScopeProcessor +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement +import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyFileImports +import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImport +import org.jetbrains.plugins.groovy.lang.resolve.imports.defaultImports +import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint import org.jetbrains.plugins.groovy.util.flatten internal class GroovyFileImportsImpl( - override val regularImports: Collection, - override val staticImports: Collection, - override val starImports: Collection, - override val staticStarImports: Collection + override val file: GroovyFile, + private val imports: Map, Collection>, + private val statementToImport: Map, + private val importToStatement: Map ) : GroovyFileImports { - override val allNamedImports: Collection = flatten(regularImports, staticImports) + @Suppress("UNCHECKED_CAST") + private fun getImports(kind: ImportKind): Collection { + val collection = imports[kind] ?: return emptyList() + return collection as Collection + } - override val allStarImports: Collection = flatten(starImports, staticStarImports) + private val regularImports get() = getImports(ImportKind.Regular) + private val staticImports get() = getImports(ImportKind.Static) + override val starImports get() = getImports(ImportKind.Star) + override val staticStarImports get() = getImports(ImportKind.StaticStar) + override val allNamedImports = flatten(getImports(ImportKind.Regular), getImports(ImportKind.Static)) + private val allStarImports = flatten(getImports(ImportKind.Star), getImports(ImportKind.StaticStar)) - override val allImports: Collection = flatten(regularImports, staticImports, starImports, staticStarImports) + private fun addStatement(state: ResolveState, import: GroovyImport): ResolveState { + val statement = importToStatement[import] ?: return state + return state.put(ClassHint.RESOLVE_CONTEXT, statement) + } - override fun toString(): String = "Regular: ${regularImports.size}; static: ${staticImports.size}; " + - "*: ${starImports.size}; static *: ${staticStarImports.size}" + @Suppress("LoopToCallChain") + private fun Collection.doProcess(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { + for (import in this) { + if (!import.processDeclarations(processor, addStatement(state, import), place, file)) return false + } + return true + } + + override fun processStaticImports(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { + return staticImports.doProcess(processor, state, place) + } + + override fun processAllNamedImports(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { + return allNamedImports.doProcess(processor, state, place) + } + + override fun processAllStarImports(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { + return allStarImports.doProcess(processor, state, place) + } + + override fun processDefaultImports(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { + return defaultImports.doProcess(processor, state, place) + } + + override fun findUnneecessaryStatements(): Collection { + return statementToImport.filterValues { it.isUnnecessary(this) }.keys + } + + override fun findUnresolvedStatements(names: Collection): Collection { + if (names.isEmpty()) return emptyList() + + val result = HashSet() + + for (import in starImports) { + val statement = importToStatement[import] ?: continue + if (import.resolve(file) == null) { + result += statement + } + } + + for (import in allNamedImports) { + if (import.name !in names) continue + val statement = importToStatement[import] ?: continue + if (import.resolve(file) == null) { + result += statement + } + } + + return result + } + + override fun toString(): String = "Regular: ${regularImports.size}; " + + "static: ${staticImports.size}; " + + "*: ${starImports.size}; " + + "static *: ${staticStarImports.size}" } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyImportCollector.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyImportCollector.kt new file mode 100644 index 000000000000..924da049d1cb --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyImportCollector.kt @@ -0,0 +1,70 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve.imports.impl + +import com.intellij.openapi.util.text.StringUtil.getPackageName +import com.intellij.openapi.util.text.StringUtil.getShortName +import com.intellij.util.reverse +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement +import org.jetbrains.plugins.groovy.lang.resolve.Import +import org.jetbrains.plugins.groovy.lang.resolve.ImportType +import org.jetbrains.plugins.groovy.lang.resolve.imports.* + +class GroovyImportCollector(private val file: GroovyFile) { + + private val statementToImport = mutableMapOf() + private val imports = HashMap, LinkedHashMap>() + + @Suppress("UNCHECKED_CAST") + private fun getMap(kind: ImportKind): LinkedHashMap { + val map = imports.getOrPut(kind) { LinkedHashMap() } + return map as LinkedHashMap + } + + private fun addImport(import: RegularImport) { + getMap(ImportKind.Regular)[import.name] = import + } + + private fun addImport(import: StaticImport) { + getMap(ImportKind.Static)[import.name] = import + } + + private fun addImport(import: StarImport) { + getMap(ImportKind.Star)[import.packageFqn] = import + } + + private fun addImport(import: StaticStarImport) { + getMap(ImportKind.StaticStar)[import.classFqn] = import + } + + private fun addImport(import: GroovyImport) = when (import) { + is RegularImport -> addImport(import) + is StaticImport -> addImport(import) + is StarImport -> addImport(import) + is StaticStarImport -> addImport(import) + else -> error("Unsupported import. Class: ${import.javaClass}; toString: ${import}") + } + + internal fun addImportFromStatement(statement: GrImportStatement) { + val import = statement.import ?: return + statementToImport[statement] = import + addImport(import) + } + + internal fun addImportFromContributor(contributedImport: Import) { + val name = contributedImport.name + when (contributedImport.type) { + ImportType.REGULAR -> addImport(RegularImport(name, getShortName(name))) + ImportType.STATIC -> addImport(StaticImport(getPackageName(name), getShortName(name))) + ImportType.STAR -> addImport(StarImport(name)) + ImportType.STATIC_STAR -> addImport(StaticStarImport(name)) + } + } + + internal fun build(): GroovyFileImports = GroovyFileImportsImpl( + file, + imports.mapValues { (_, map) -> map.values.toList() }.toMap(), + statementToImport, + statementToImport.reverse() + ) +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/ImportKind.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/ImportKind.kt new file mode 100644 index 000000000000..2cdb318b3f15 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/ImportKind.kt @@ -0,0 +1,12 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve.imports.impl + +import org.jetbrains.plugins.groovy.lang.resolve.imports.* + +@kotlin.Suppress("unused") // T of ImportKind +internal sealed class ImportKind { + internal object Regular : ImportKind() + internal object Static : ImportKind() + internal object Star : ImportKind() + internal object StaticStar : ImportKind() +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/impl.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/impl.kt deleted file mode 100644 index a973c8965486..000000000000 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/impl.kt +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package org.jetbrains.plugins.groovy.lang.resolve.imports.impl - -import com.intellij.openapi.util.text.StringUtil -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile -import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase -import org.jetbrains.plugins.groovy.lang.resolve.GrImportContributor -import org.jetbrains.plugins.groovy.lang.resolve.Import -import org.jetbrains.plugins.groovy.lang.resolve.ImportType -import org.jetbrains.plugins.groovy.lang.resolve.imports.* - -internal val defaultRegularImports = GroovyFileBase.IMPLICITLY_IMPORTED_CLASSES.map(::RegularImport) -internal val defaultStarImports = GroovyFileBase.IMPLICITLY_IMPORTED_PACKAGES.map(::StarImport) - -internal fun GroovyFile.doGetImports(): GroovyFileImports { - val regularImports = LinkedHashMap() - val starImports = LinkedHashMap() - val staticImports = LinkedHashMap() - val staticStarImports = LinkedHashMap() - - fun addImport(import: GroovyImport?) { - when (import) { - is RegularImport -> regularImports[import.name] = import - is StaticImport -> staticImports[import.name] = import - is StarImport -> starImports[import.packageFqn] = import - is StaticStarImport -> staticStarImports[import.classFqn] = import - null -> return - else -> unsupportedImport(import) - } - } - - for (statement in importStatements) { - addImport(statement.import) - } - - for (contributor in GrImportContributor.EP_NAME.extensions) { - contributor.getImports(this).forEach { - addImport(createImportFromContributor(it)) - } - } - - return GroovyFileImportsImpl( - regularImports.values.toList(), - staticImports.values.toList(), - starImports.values.toList(), - staticStarImports.values.toList() - ) -} - -private fun createImportFromContributor(contributedImport: Import): GroovyImport { - val type = contributedImport.type - val name = contributedImport.name - return when (type) { - ImportType.REGULAR -> RegularImport(name) - ImportType.STATIC -> { - val packageName = StringUtil.getPackageName(name) - val memberName = StringUtil.getShortName(name) - StaticImport(packageName, memberName) - } - ImportType.STAR -> StarImport(name) - ImportType.STATIC_STAR -> StaticStarImport(name) - } -} - -private fun unsupportedImport(import: GroovyImport): Nothing = error("Unsupported import. Class: ${import.javaClass}; toString: ${import}") diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/imports.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/imports.kt index 185f48c3aaf6..45fb313ba002 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/imports.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/imports.kt @@ -6,16 +6,23 @@ package org.jetbrains.plugins.groovy.lang.resolve.imports import com.intellij.openapi.util.Key import com.intellij.psi.util.CachedValueProvider.Result import com.intellij.psi.util.CachedValuesManager +import gnu.trove.THashSet import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement import org.jetbrains.plugins.groovy.lang.psi.util.ErrorUtil -import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.defaultRegularImports -import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.defaultStarImports -import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.doGetImports +import org.jetbrains.plugins.groovy.lang.resolve.GrImportContributor +import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.GroovyImportCollector +import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.RegularImportHashingStrategy +import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.StarImportHashingStrategy + +internal val defaultRegularImports = GroovyFileBase.IMPLICITLY_IMPORTED_CLASSES.map(::RegularImport) +internal val defaultStarImports = GroovyFileBase.IMPLICITLY_IMPORTED_PACKAGES.map(::StarImport) +internal val defaultImports = defaultStarImports + defaultRegularImports +internal val defaultRegularImportsSet = THashSet(defaultRegularImports, RegularImportHashingStrategy) +internal val defaultStarImportsSet = THashSet(defaultStarImports, StarImportHashingStrategy) -@JvmField val importedNameKey = Key.create("groovy.imported.via.name") -val defaultImports = defaultStarImports + defaultRegularImports fun GroovyFile.getImports(): GroovyFileImports { return CachedValuesManager.getCachedValue(this) { @@ -23,4 +30,18 @@ fun GroovyFile.getImports(): GroovyFileImports { } } +private fun GroovyFile.doGetImports(): GroovyFileImports { + val collector = GroovyImportCollector(this) + + for (statement in importStatements) { + collector.addImportFromStatement(statement) + } + + for (contributor in GrImportContributor.EP_NAME.extensions) { + contributor.getImports(this).forEach(collector::addImportFromContributor) + } + + return collector.build() +} + val GroovyFile.validImportStatements: List get() = importStatements.filterNot(ErrorUtil::containsError) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/unusedImports.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/unusedImports.kt index 124d2993d75b..09018265afd1 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/unusedImports.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/unusedImports.kt @@ -1,29 +1,15 @@ // Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. @file:JvmName("GroovyUnusedImportUtil") -@file:Suppress("LoopToCallChain") package org.jetbrains.plugins.groovy.lang.resolve.imports -import com.intellij.openapi.util.text.StringUtil.getPackageName import com.intellij.psi.PsiElement import com.intellij.psi.PsiRecursiveElementWalkingVisitor -import com.intellij.psi.ResolveState import com.intellij.util.containers.HashSet -import gnu.trove.THashSet import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement import org.jetbrains.plugins.groovy.lang.psi.GroovyFile import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition -import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.RegularImportHashingStrategy -import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.StarImportHashingStrategy -import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.defaultRegularImports -import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.defaultStarImports -import org.jetbrains.plugins.groovy.lang.resolve.processClassesInFile -import org.jetbrains.plugins.groovy.lang.resolve.processClassesInPackage -import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassProcessor - -private val defaultRegularImportsSet = THashSet(defaultRegularImports, RegularImportHashingStrategy) -private val defaultStarImportsSet = THashSet(defaultStarImports, StarImportHashingStrategy) fun unusedImports(file: GroovyFile): Set { val result = file.validImportStatements.toMutableSet() @@ -39,18 +25,10 @@ fun usedImports(file: GroovyFile): Set { file.accept(searcher) searcher.results } - assertShadowed(file, referencedStatements) val usedStatements = HashSet(referencedStatements) - usedStatements -= imports.findUnusedStarImportStatements() - usedStatements -= imports.findUnusedStaticImportStatements() - usedStatements -= imports.findUnusedRegularImportStatements(file) - - if (!unresolvedReferenceNames.isEmpty()) { - usedStatements.addAll(imports.findUnresolvedNamedImports(file, unresolvedReferenceNames)) - usedStatements.addAll(imports.findUnresolvedStarImports(file)) - } - + usedStatements -= imports.findUnneecessaryStatements() + usedStatements += imports.findUnresolvedStatements(unresolvedReferenceNames) return usedStatements } @@ -81,115 +59,9 @@ private class ReferencedImportsSearcher : PsiRecursiveElementWalkingVisitor() { unresolvedReferenceNames.add(refName) } else { - for (result in results) { - val resolveContext = result.currentFileResolveContext - if (resolveContext is GrImportStatement) { - referencedStatements.add(resolveContext as GrImportStatement?) - } + results.mapNotNullTo(referencedStatements) { + it.currentFileResolveContext as? GrImportStatement } } } } - - -private fun assertShadowed(file: GroovyFile, referencedStatements: Collection) { - val allStatements = file.validImportStatements - val shadowedStatements = allStatements - file.getImports().allImports.getStatements() - val intersection = referencedStatements.intersect(shadowedStatements) - assert(intersection.isEmpty()) { - """|Shadowed imports found in referenced. - |Intersection: - |${intersection.map { it.text }} - |Shadowed: - |${shadowedStatements.map { it.text }} - |Referenced: - |${referencedStatements.map { it.text }}""".trimMargin() - } -} - -private fun GroovyFileImports.findUnusedRegularImportStatements(file: GroovyFile): List = findUnusedRegularImports( - file).getStatements() - -private fun GroovyFileImports.findUnusedStaticImportStatements(): List = findUnusedStaticImports().getStatements() - -private fun GroovyFileImports.findUnusedStarImportStatements(): List = findUnusedStarImports().getStatements() - -private fun GroovyFileImports.findUnusedRegularImports(file: GroovyFile): List { - return regularImports.filter { - val statement = it.statement - statement != null && isUnused(file, statement, it) - } -} - -private fun GroovyFileImports.findUnusedStaticImports(): List { - return staticImports.filter { - it.statement != null && isUnused(it) - } -} - -private fun GroovyFileImports.findUnusedStarImports(): List { - return starImports.filter { - it.statement != null && isUnused(it) - } -} - -private fun GroovyFileImports.isUnused(file: GroovyFile, statement: GrImportStatement, import: RegularImport): Boolean { - if (import.isAliased) return false - - val processor = ClassProcessor(import.name, file) - val state = ResolveState.initial() - - for (_import in staticImports) { - if (!_import.processDeclarations(processor, state, statement, file)) return false - } - - val starImport = StarImport(getPackageName(import.classFqn)) - if (starImport.packageFqn == file.packageName) return true - - if (!file.processClassesInFile(processor, state)) return false - if (!file.processClassesInPackage(processor, state)) return false - - if (starImport in starImports) return true - - for (_import in starImports) { - if (!_import.processDeclarations(processor, state, statement, file)) return false - } - - for (_import in staticStarImports) { - if (!_import.processDeclarations(processor, state, statement, file)) return false - } - - val results = processor.results - assert(results.isEmpty()) { - "Processor returned true, but there are ${results.size} results: $results" - } - - return import in defaultRegularImportsSet || starImport in defaultStarImportsSet -} - -private fun GroovyFileImports.isUnused(import: StaticImport): Boolean { - if (import.isAliased) return false - return StaticStarImport(import.classFqn) in staticStarImports -} - -private fun isUnused(import: StarImport): Boolean { - return import in defaultStarImportsSet -} - -private fun Collection.getStatements(): List { - return mapNotNull { - it.statement - } -} - -private fun GroovyFileImports.findUnresolvedNamedImports(file: GroovyFile, names: Collection): Collection { - return allNamedImports.filter { - it.statement != null && it.name in names && it.resolve(file) == null - }.getStatements() -} - -private fun GroovyFileImports.findUnresolvedStarImports(file: GroovyFile): List { - return starImports.filter { - it.statement != null && it.resolve(file) == null - }.getStatements() -} From 7297339487bf47e57f85579afaa491f309737f25 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Thu, 16 Nov 2017 02:53:10 +0300 Subject: [PATCH 31/43] [groovy] make GroovyCodeFragment provide its own GroovyFileImports --- .../fragments/GroovyCodeFragment.java | 206 ++++++------------ .../imports/impl/GroovyImportCollector.kt | 49 +++-- 2 files changed, 99 insertions(+), 156 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/debugger/fragments/GroovyCodeFragment.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/debugger/fragments/GroovyCodeFragment.java index 094bf2e4481b..f266340ddea1 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/debugger/fragments/GroovyCodeFragment.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/debugger/fragments/GroovyCodeFragment.java @@ -1,44 +1,23 @@ -/* - * Copyright 2000-2016 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.debugger.fragments; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.ClearableLazyValue; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.impl.PsiManagerEx; import com.intellij.psi.impl.file.impl.FileManager; import com.intellij.psi.impl.source.tree.FileElement; -import com.intellij.psi.scope.NameHint; -import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.testFramework.LightVirtualFile; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyFileType; -import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnAmbiguousClosureContainer; -import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyFileImpl; -import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyImportHelper.ImportKind; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.Map; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; +import org.jetbrains.plugins.groovy.lang.resolve.imports.*; +import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.GroovyImportCollector; /** * @author ven @@ -53,8 +32,9 @@ public class GroovyCodeFragment extends GroovyFileImpl implements JavaCodeFragme /** * map from a class's imported name (e.g. its short name or alias) to its qualified name */ - private final LinkedHashMap myPseudoImports = ContainerUtil.newLinkedHashMap(); - private final ArrayList myOnDemandImports = ContainerUtil.newArrayList(); + private final GroovyImportCollector myImportCollector = new GroovyImportCollector(this); + private final ClearableLazyValue myFileImports = ClearableLazyValue.create(() -> myImportCollector.build()); + private FileViewProvider myViewProvider = null; public GroovyCodeFragment(Project project, CharSequence text) { @@ -93,45 +73,65 @@ public class GroovyCodeFragment extends GroovyFileImpl implements JavaCodeFragme */ @Override public String importsToString() { - if (myPseudoImports.isEmpty()) return ""; + if (myImportCollector.isEmpty()) return ""; - StringBuilder buffer = new StringBuilder(); - for (Map.Entry entry : myPseudoImports.entrySet()) { - final String importedName = entry.getKey(); - final GrImportStatement anImport = entry.getValue(); - - - //buffer.append(anImport.isStatic() ? "+" : "-"); - final String qname = anImport.getImportReference().getClassNameText(); - - buffer.append(qname); - buffer.append(':').append(importedName); + final StringBuilder buffer = new StringBuilder(); + for (GroovyImport anImport : myImportCollector.getAllImports()) { + if (anImport instanceof RegularImport) { + buffer + .append(((RegularImport)anImport).getClassFqn()) + .append(':') + .append(((RegularImport)anImport).getName()); + } + else if (anImport instanceof StaticImport) { + buffer + .append(((StaticImport)anImport).getClassFqn()) + .append('.') + .append(((StaticImport)anImport).getMemberName()) + .append(':') + .append(((StaticImport)anImport).getName()); + } + else if (anImport instanceof GroovyStarImport) { + buffer.append(((GroovyStarImport)anImport).getFqn()); + } + else { + PsiUtil.LOG.warn("Unsupported import. Class: " + anImport.getClass()); + } buffer.append(','); } - for (GrImportStatement anImport : myOnDemandImports) { - //buffer.append(anImport.isStatic() ? "+" : "-"); - - String packName = anImport.getImportReference().getClassNameText(); - buffer.append(packName); - buffer.append(','); - } buffer.deleteCharAt(buffer.length() - 1); return buffer.toString(); } @Override public void addImportsFromString(String imports) { + myFileImports.drop(); for (String anImport : imports.split(",")) { - int colon = anImport.indexOf(':'); + addImport(anImport); + } + } - if (colon >= 0) { - String qname = anImport.substring(0, colon); - String importedName = anImport.substring(colon + 1); - myPseudoImports.put(importedName, createSingleImport(qname, importedName)); + private void addImport(@NotNull String importString) { + int colon = importString.indexOf(':'); + if (colon >= 0) { + final String qname = importString.substring(0, colon); + final String importedName = importString.substring(colon + 1); + final boolean isStatic = JavaPsiFacade.getInstance(getProject()).findClass(qname, getResolveScope()) == null; + if (isStatic) { + myImportCollector.addStaticImport(StringUtil.getPackageName(qname), StringUtil.getShortName(qname), importedName); } else { - myOnDemandImports.add(createImportOnDemand(anImport)); + myImportCollector.addRegularImport(qname, importedName); + } + } + else { + final boolean isStatic = JavaPsiFacade.getInstance(getProject()).findClass(importString, getResolveScope()) != null; + if (isStatic) { + myImportCollector.addStaticStarImport(importString); + } + else { + myImportCollector.addStarImport(importString); } } } @@ -185,26 +185,12 @@ public class GroovyCodeFragment extends GroovyFileImpl implements JavaCodeFragme return myThisType; } - @Override - protected boolean processImports(PsiScopeProcessor processor, - @NotNull ResolveState state, - @Nullable PsiElement lastParent, - @NotNull PsiElement place, - @NotNull GrImportStatement[] importStatements, - @NotNull ImportKind kind, - @Nullable Boolean processStatic) { - return super.processImports(processor, state, lastParent, place, importStatements, kind, processStatic) && ( - kind == ImportKind.ON_DEMAND - ? processImportsOnDemand(processor, state, lastParent, place, processStatic) - : !(kind == ImportKind.ALIAS && !processSingleImports(processor, state, lastParent, place, processStatic)) - ); - } - + @SuppressWarnings("MethodDoesntCallSuperMethod") @Override protected GroovyCodeFragment clone() { final GroovyCodeFragment clone = (GroovyCodeFragment)cloneImpl((FileElement)calcTreeElement().clone()); clone.myOriginalFile = this; - clone.myPseudoImports.putAll(myPseudoImports); + clone.myImportCollector.setFrom(myImportCollector); FileManager fileManager = ((PsiManagerEx)getManager()).getFileManager(); SingleRootFileViewProvider cloneViewProvider = (SingleRootFileViewProvider)fileManager.createFileViewProvider(new LightVirtualFile( getName(), @@ -215,79 +201,13 @@ public class GroovyCodeFragment extends GroovyFileImpl implements JavaCodeFragme return clone; } - private boolean processImportsOnDemand(PsiScopeProcessor processor, ResolveState state, PsiElement parent, PsiElement place, Boolean processStatic) { - if (processStatic == null) return processImportsOnDemand(processor, state, parent, place, false) && - processImportsOnDemand(processor, state, parent, place, true); - for (GrImportStatement anImport : myOnDemandImports) { - if (processStatic != anImport.isStatic()) continue; - if (!anImport.processDeclarations(processor, state, parent, place)) { - return false; - } - } - return true; - } - - private boolean processSingleImports(PsiScopeProcessor processor, - @NotNull ResolveState state, - PsiElement lastParent, - PsiElement place, - Boolean processStatic) { - if (processStatic == null) return processSingleImports(processor, state, lastParent, place, false) && - processSingleImports(processor, state, lastParent, place, true); - NameHint nameHint = processor.getHint(NameHint.KEY); - String name = nameHint != null ? nameHint.getName(state) : null; - - if (name != null) { - final GrImportStatement anImport = myPseudoImports.get(name); - if (anImport != null && processStatic == anImport.isStatic()) { - if (!anImport.processDeclarations(processor, state, lastParent, place)) { - return false; - } - } - } - else { - for (GrImportStatement anImport : myPseudoImports.values()) { - if (processStatic != anImport.isStatic()) continue; - if (!anImport.processDeclarations(processor, state, lastParent, place)) { - return false; - } - } - } - return true; - } - - @Nullable - private GrImportStatement createImportOnDemand(@NotNull String qname) { - final PsiClass aClass = JavaPsiFacade.getInstance(getProject()).findClass(qname, getResolveScope()); - final boolean isStatic = aClass != null; - - final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(getProject()); - try { - return factory.createImportStatement(qname, isStatic, true, null, this); - } - catch (IncorrectOperationException e) { - return null; - } - } - - @Nullable - private GrImportStatement createSingleImport(@NotNull String qname, @Nullable String importedName) { - final PsiClass aClass = JavaPsiFacade.getInstance(getProject()).findClass(qname, getResolveScope()); - final boolean isStatic = aClass == null; - - final String className = PsiNameHelper.getShortClassName(qname); - final String alias = importedName == null || className.equals(importedName) ? null : importedName; - final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(getProject()); - try { - return factory.createImportStatement(qname, isStatic, false, alias, this); - } - catch (IncorrectOperationException e) { - return null; - } - } - public void clearImports() { - myPseudoImports.clear(); - myOnDemandImports.clear(); + myFileImports.drop(); + myImportCollector.clear(); + } + + @Override + protected GroovyFileImports getImports() { + return myFileImports.getValue(); } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyImportCollector.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyImportCollector.kt index 924da049d1cb..e3f0f5371541 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyImportCollector.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyImportCollector.kt @@ -15,36 +15,59 @@ class GroovyImportCollector(private val file: GroovyFile) { private val statementToImport = mutableMapOf() private val imports = HashMap, LinkedHashMap>() + val isEmpty get() = imports.values.all { it.isEmpty() } + + fun clear() { + imports.clear() + } + + fun setFrom(collector: GroovyImportCollector) { + imports.clear() + imports.putAll(collector.imports) + } + + val allImports: Collection get() = imports.values.flatMap { it.values } + @Suppress("UNCHECKED_CAST") private fun getMap(kind: ImportKind): LinkedHashMap { val map = imports.getOrPut(kind) { LinkedHashMap() } return map as LinkedHashMap } - private fun addImport(import: RegularImport) { + private fun addRegularImport(import: RegularImport) { getMap(ImportKind.Regular)[import.name] = import } - private fun addImport(import: StaticImport) { + private fun addStaticImport(import: StaticImport) { getMap(ImportKind.Static)[import.name] = import } - private fun addImport(import: StarImport) { + private fun addStarImport(import: StarImport) { getMap(ImportKind.Star)[import.packageFqn] = import } - private fun addImport(import: StaticStarImport) { + private fun addStaticStarImport(import: StaticStarImport) { getMap(ImportKind.StaticStar)[import.classFqn] = import } private fun addImport(import: GroovyImport) = when (import) { - is RegularImport -> addImport(import) - is StaticImport -> addImport(import) - is StarImport -> addImport(import) - is StaticStarImport -> addImport(import) + is RegularImport -> addRegularImport(import) + is StaticImport -> addStaticImport(import) + is StarImport -> addStarImport(import) + is StaticStarImport -> addStaticStarImport(import) else -> error("Unsupported import. Class: ${import.javaClass}; toString: ${import}") } + fun addRegularImport(classFqn: String, name: String) = addRegularImport(RegularImport(classFqn, name)) + + fun addStaticImport(classFqn: String, memberName: String) = addStaticImport(classFqn, memberName, memberName) + + fun addStaticImport(classFqn: String, memberName: String, name: String) = addStaticImport(StaticImport(classFqn, memberName, name)) + + fun addStarImport(packageFqn: String) = addStarImport(StarImport(packageFqn)) + + fun addStaticStarImport(classFqn: String) = addStaticStarImport(StaticStarImport(classFqn)) + internal fun addImportFromStatement(statement: GrImportStatement) { val import = statement.import ?: return statementToImport[statement] = import @@ -54,14 +77,14 @@ class GroovyImportCollector(private val file: GroovyFile) { internal fun addImportFromContributor(contributedImport: Import) { val name = contributedImport.name when (contributedImport.type) { - ImportType.REGULAR -> addImport(RegularImport(name, getShortName(name))) - ImportType.STATIC -> addImport(StaticImport(getPackageName(name), getShortName(name))) - ImportType.STAR -> addImport(StarImport(name)) - ImportType.STATIC_STAR -> addImport(StaticStarImport(name)) + ImportType.REGULAR -> addRegularImport(name, getShortName(name)) + ImportType.STATIC -> addStaticImport(getPackageName(name), getShortName(name)) + ImportType.STAR -> addStarImport(name) + ImportType.STATIC_STAR -> addStaticStarImport(name) } } - internal fun build(): GroovyFileImports = GroovyFileImportsImpl( + fun build(): GroovyFileImports = GroovyFileImportsImpl( file, imports.mapValues { (_, map) -> map.values.toList() }.toMap(), statementToImport, From e877d81ec807b3fe2613987799864a80863a6c4c Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Thu, 16 Nov 2017 19:24:32 +0300 Subject: [PATCH 32/43] [util] add PsiElement.contextOfType() --- .../src/com/intellij/psi/util/psiTreeUtil.kt | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/util/psiTreeUtil.kt b/java/java-impl/src/com/intellij/psi/util/psiTreeUtil.kt index e7021d3a5f0f..b0e642673b9d 100644 --- a/java/java-impl/src/com/intellij/psi/util/psiTreeUtil.kt +++ b/java/java-impl/src/com/intellij/psi/util/psiTreeUtil.kt @@ -1,18 +1,4 @@ -/* - * Copyright 2000-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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.psi.util import com.intellij.psi.PsiElement @@ -30,3 +16,10 @@ inline fun PsiElement.parentsOfType(): Sequence = pa fun PsiElement.parentsOfType(clazz: Class): Sequence = parents().filterIsInstance(clazz) fun PsiElement.parents(): Sequence = generateSequence(this) { it.parent } + + +inline fun PsiElement.contextOfType(): T? = contextOfType(T::class) + +fun PsiElement.contextOfType(vararg classes: KClass): T? { + return PsiTreeUtil.getContextOfType(this, *classes.map { it.java }.toTypedArray()) +} From 027218b228ac10dc8b8b999b72b1424d5596de39 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Thu, 16 Nov 2017 19:32:37 +0300 Subject: [PATCH 33/43] [groovy] add recursion assert in ResolveClassInNewTest --- .../groovy/lang/resolve/ResolveClassInNewTest.groovy | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassInNewTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassInNewTest.groovy index 666db03ccb8e..3ec35bcda4c2 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassInNewTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassInNewTest.groovy @@ -8,6 +8,8 @@ import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.util.TestUtils +import static com.intellij.openapi.util.RecursionManager.assertOnRecursionPrevention + @CompileStatic class ResolveClassInNewTest extends LightGroovyTestCase { @@ -15,6 +17,12 @@ class ResolveClassInNewTest extends LightGroovyTestCase { final String basePath = TestUtils.testDataPath + '/resolve/classInNew' + @Override + void setUp() throws Exception { + super.setUp() + assertOnRecursionPrevention(testRootDisposable) + } + private void doDirectoryTest(String fqn) { final name = getTestName() fixture.copyDirectoryToProject "$name/src", '/' From 95ce424ad9e14bae02f4ac4dc92aff8774f8f7af Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Thu, 16 Nov 2017 19:33:28 +0300 Subject: [PATCH 34/43] [groovy] add and use inners caches --- .../groovy/lang/psi/util/GrClassImplUtil.java | 69 +++------- .../lang/resolve/GrCodeReferenceResolver.kt | 108 +++++---------- .../lang/resolve/caches/MembersCache.kt | 11 ++ .../groovy/lang/resolve/caches/innersCache.kt | 80 +++++++++++ .../plugins/groovy/lang/resolve/inners.kt | 129 ++++++++++++++++++ 5 files changed, 269 insertions(+), 128 deletions(-) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/MembersCache.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/innersCache.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/inners.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java index 34470ed42a5e..84ab8e7729c0 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java @@ -2,15 +2,11 @@ package org.jetbrains.plugins.groovy.lang.psi.util; -import com.intellij.openapi.diagnostic.Attachment; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.RecursionManager; -import com.intellij.openapi.util.Trinity; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; -import com.intellij.psi.impl.DebugUtil; import com.intellij.psi.impl.PsiClassImplUtil; import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.scope.ElementClassHint; @@ -33,7 +29,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlo import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrEnumConstantInitializer; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrReferenceList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinitionBody; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; @@ -168,10 +163,14 @@ public class GrClassImplUtil { return list.getReferencedTypes(); } - @NotNull public static PsiClass[] getInterfaces(GrTypeDefinition grType) { - final PsiClassType[] implementsListTypes = grType.getImplementsListTypes(); + return getInterfaces(grType, true); + } + + @NotNull + public static PsiClass[] getInterfaces(GrTypeDefinition grType, boolean includeSynthetic) { + final PsiClassType[] implementsListTypes = grType.getImplementsListTypes(includeSynthetic); List result = new ArrayList<>(implementsListTypes.length); for (PsiClassType type : implementsListTypes) { final PsiClass psiClass = type.resolve(); @@ -284,17 +283,21 @@ public class GrClassImplUtil { } } - final GrTypeDefinitionBody body = grType.getBody(); - if (body != null) { - if (ResolveUtil.shouldProcessClasses(classHint)) { - for (PsiClass innerClass : getInnerClassesForResolve(grType, lastParent, place)) { - if (name != null && !name.equals(innerClass.getName())) continue; - if (!processor.execute(innerClass, state)) return false; + if (ResolveUtil.shouldProcessClasses(classHint)) { + Map classes = CollectClassMembersUtil.getAllInnerClasses(grType, true); + if (name == null) { + for (CandidateInfo info : classes.values()) { + if (!processor.execute(info.getElement(), state)) return false; + } + } + else { + CandidateInfo info = classes.get(name); + if (info != null) { + if (!processor.execute(info.getElement(), state)) return false; } } } - return true; } @@ -371,44 +374,6 @@ public class GrClassImplUtil { } } - @NotNull - private static List getInnerClassesForResolve(@NotNull final GrTypeDefinition grType, - @Nullable final PsiElement lastParent, - @NotNull final PsiElement place) { - if (lastParent instanceof GrReferenceList || PsiTreeUtil.getParentOfType(place, GrReferenceList.class) != null) { - return Arrays.asList(grType.getCodeInnerClasses()); - } - - boolean includeSynthetic = !PsiTreeUtil.isContextAncestor(grType, place, true); - Object key = Trinity.create(grType, lastParent, place); - List classes = RecursionManager.doPreventingRecursion(key, false, () -> { - List result = new ArrayList<>(); - for (CandidateInfo info : CollectClassMembersUtil.getAllInnerClasses(grType, includeSynthetic).values()) { - final PsiClass inner = (PsiClass)info.getElement(); - final PsiClass containingClass = inner.getContainingClass(); - if (containingClass == null) { - PsiFile file = grType.getContainingFile(); - LOG.error( - "Contating class must not be null. Name: " + inner.getName() + ", class: :" + inner.getClass(), - new Attachment(file.getVirtualFile().getPresentableUrl(), DebugUtil.psiToString(file, false)) - ); - continue; - } - - if (lastParent == null || !containingClass.isInterface() || PsiTreeUtil.isAncestor(containingClass, place, false)) { - ContainerUtil.addIfNotNull(result, inner); - } - } - return result; - }); - - if (classes == null) { - return Arrays.asList(grType.getCodeInnerClasses()); - } - - return classes; - } - public static boolean isSameDeclaration(PsiElement place, PsiElement element) { if (element instanceof GrAccessorMethod) element = ((GrAccessorMethod)element).getProperty(); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt index 0bc3cccf815e..aa13f05d2b90 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt @@ -1,12 +1,11 @@ // Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -@file:Suppress("LoopToCallChain") package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.psi.* import com.intellij.psi.scope.PsiScopeProcessor +import com.intellij.psi.util.contextOfType import com.intellij.psi.util.parentOfType -import com.intellij.util.SmartList import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement import org.jetbrains.plugins.groovy.lang.psi.GroovyFile import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult @@ -171,20 +170,32 @@ private fun PsiClass.getPackage(): PsiPackage? { return JavaPsiFacade.getInstance(file.project).findPackage(name) } -@Suppress("LiftReturnOrAssignment") fun GrCodeReferenceElement.processClasses(processor: PsiScopeProcessor, state: ResolveState): Boolean { val qualifier = qualifier if (qualifier == null) { - return processAsUnqualifiedType(processor, state) + return processUnqualified(processor, state) } else { return processQualifier(qualifier, processor, state) } } -private fun GrCodeReferenceElement.processAsUnqualifiedType(processor: PsiScopeProcessor, state: ResolveState): Boolean { - return processInnerClasses(processor, state) && - containingFile.treeWalkUp(processor, state, this) +private fun GrCodeReferenceElement.processUnqualified(processor: PsiScopeProcessor, state: ResolveState): Boolean { + if (!processInnerClasses(processor, state)) return false + // When all inner classes are processed, it's time to process file level declarations (i.e. imports). + // There is no point in processing imports in dummy files. + val file = containingFile.skipDummies() ?: return true + return file.treeWalkUp(processor, state, this) +} + +private fun GrCodeReferenceElement.processInnerClasses(processor: PsiScopeProcessor, state: ResolveState): Boolean { + val currentClass = contextOfType() ?: return true + + if (canResolveToInnerClassOfCurrentClass()) { + if (!currentClass.processInnerInHierarchy(processor, state, this)) return false + } + + return currentClass.processInnersInOuters(processor, state, this) } private fun GrCodeReferenceElement.processQualifier(qualifier: GrCodeReferenceElement, @@ -192,85 +203,30 @@ private fun GrCodeReferenceElement.processQualifier(qualifier: GrCodeReferenceEl state: ResolveState): Boolean { for (result in qualifier.multiResolve(false)) { val clazz = result.element as? PsiClass ?: continue - if (!processInnersInHierarchy(clazz, processor, state.put(PsiSubstitutor.KEY, result.substitutor), this)) return false + if (!clazz.processDeclarations(processor, state.put(PsiSubstitutor.KEY, result.substitutor), null, this)) return false } return true } -private fun GrReferenceElement<*>.processInnerClasses(processor: PsiScopeProcessor, state: ResolveState): Boolean { - val currentClass = parentOfType() ?: return true - - if (canResolveToInnerClassOrCurrentClass()) { - if (!processInnersInHierarchy(currentClass, processor, state, this)) return false - } - - val outers = currentClass.collectOuterClasses().reversed() - for (outer in outers) { - if (!processInnerClassesInClassAndInterfaces(outer, false, processor, state, this)) return false - } - return true -} - -private fun GrReferenceElement<*>.canResolveToInnerClassOrCurrentClass(): Boolean { - val parent = parent +private fun GrCodeReferenceElement.canResolveToInnerClassOfCurrentClass(): Boolean { + val parent = getActualParent() return parent !is GrExtendsClause && parent !is GrImplementsClause && (parent !is GrAnnotation || parent.classReference != this) && // annotation's can't be inner classes of current class (parent !is GrAnonymousClassDefinition || parent.baseClassReferenceGroovy != this) } -private fun processInnersInHierarchy(clazz: PsiClass, - processor: PsiScopeProcessor, - state: ResolveState, - place: PsiElement): Boolean { - if (!processInnerClassesInClassAndInterfaces(clazz, false, processor, state, place)) return false +/** + * Reference element may be created from stub. In this case containing file will be dummy, and its context will be reference parent + */ +private fun GrCodeReferenceElement.getActualParent(): PsiElement? = containingFile.context ?: parent - var superClass: PsiClass? = clazz.superClass - while (superClass != null) { - if (!processInnerClassesInClassAndInterfaces(superClass, true, processor, state, place)) return false - superClass = superClass.superClass +private fun PsiFile?.skipDummies(): PsiFile? { + var file: PsiFile? = this + while (file != null && !file.isPhysical) { + val context = file.context + if (context == null) return file + file = context.containingFile } - - return true -} - -private fun processInnerClassesInClassAndInterfaces(clazz: PsiClass, - includeSynthetic: Boolean, - processor: PsiScopeProcessor, - state: ResolveState, - place: PsiElement): Boolean { - val name = processor.getName(state) - if (name == null) { - for (inner in CollectClassMembersUtil.getInnerClasses(clazz, includeSynthetic)) { - if (!processor.execute(inner, state)) return false - } - } - else { - val inner = if (includeSynthetic) { - clazz.findInnerClassByName(name, false) - } - else { - val inners = (clazz as? GrTypeDefinition)?.codeInnerClasses ?: clazz.innerClasses - inners.find { it.name == name } - } - if (inner != null) { - if (!processor.execute(inner, state)) return false - } - } - - for (anInterface in clazz.interfaces) { - if (!anInterface.processDeclarations(processor, state, null, place)) return false - } - - return true -} - -private fun GrTypeDefinition.collectOuterClasses(): List { - val result = SmartList() - var current: GrTypeDefinition? = containingClass as? GrTypeDefinition - while (current != null) { - result += current - current = current.containingClass as? GrTypeDefinition - } - return result + return file } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/MembersCache.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/MembersCache.kt new file mode 100644 index 000000000000..c1e790bd8e27 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/MembersCache.kt @@ -0,0 +1,11 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve.caches + +import com.intellij.psi.PsiElement +import com.intellij.psi.ResolveState +import com.intellij.psi.scope.PsiScopeProcessor + +interface MembersCache { + + fun processMembers(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/innersCache.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/innersCache.kt new file mode 100644 index 000000000000..18bfb01bcad6 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/innersCache.kt @@ -0,0 +1,80 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve.caches + +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiTypeParameter +import com.intellij.psi.ResolveState +import com.intellij.psi.scope.PsiScopeProcessor +import com.intellij.psi.util.CachedValueProvider.Result +import com.intellij.psi.util.CachedValuesManager +import com.intellij.psi.util.PsiModificationTracker +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition +import org.jetbrains.plugins.groovy.lang.resolve.getName +import org.jetbrains.plugins.groovy.lang.resolve.processInnersInHierarchyNoCache +import org.jetbrains.plugins.groovy.lang.resolve.processInnersInOutersNoCache +import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint +import org.jetbrains.plugins.groovy.lang.resolve.processors.GrScopeProcessorWithHints + +fun GrTypeDefinition.getInnersHierarchyCache(): MembersCache { + return CachedValuesManager.getCachedValue(this) { + makeResult(buildCache(this::processInnersInHierarchyNoCache)) + } +} + +fun GrTypeDefinition.getInnersOutersCache(): MembersCache { + return CachedValuesManager.getCachedValue(this) { + makeResult(buildCache(this::processInnersInOutersNoCache)) + } +} + +private fun GrTypeDefinition.makeResult(value: T): Result { + return Result.create(value, this, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT) +} + +private typealias ProcessFunction = (PsiScopeProcessor, ResolveState, PsiElement) -> Boolean + +private inline fun GrTypeDefinition.buildCache(f: ProcessFunction): MembersCache { + val processor = ClassCacheBuilderProcessor() + f(processor, ResolveState.initial(), this) + return processor.buildCache() +} + +private class ClassCacheBuilderProcessor : GrScopeProcessorWithHints(null, ClassHint.RESOLVE_KINDS_CLASS) { + + private val classMap = HashMap() + + internal fun buildCache(): MembersCache = ClassCacheImpl(classMap) + + override fun execute(element: PsiElement, state: ResolveState): Boolean { + val clazz = element as? PsiClass ?: return true + if (clazz is PsiTypeParameter) return true + + val name = clazz.name ?: return true + if (name in classMap) return true + + classMap.put(name, clazz) + + return true + } +} + +private class ClassCacheImpl(private val classMap: Map) : MembersCache { + + override fun processMembers(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { + if (classMap.isEmpty()) return true + val name = processor.getName(state) + if (name == null) { + for (clazz in classMap.values) { + if (!processor.execute(clazz, state)) return false + } + } + else { + val clazz = classMap[name] + if (clazz != null) { + if (!processor.execute(clazz, state)) return false + } + } + return true + } +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/inners.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/inners.kt new file mode 100644 index 000000000000..1ee615c09f4c --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/inners.kt @@ -0,0 +1,129 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +@file:Suppress("LoopToCallChain", "UseExpressionBody", "LiftReturnOrAssignment") + +package org.jetbrains.plugins.groovy.lang.resolve + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiElement +import com.intellij.psi.ResolveState +import com.intellij.psi.impl.PsiFileEx +import com.intellij.psi.scope.PsiScopeProcessor +import com.intellij.util.SmartList +import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition +import org.jetbrains.plugins.groovy.lang.psi.util.GrClassImplUtil +import org.jetbrains.plugins.groovy.lang.resolve.caches.getInnersHierarchyCache +import org.jetbrains.plugins.groovy.lang.resolve.caches.getInnersOutersCache + +fun GrTypeDefinition.processInnerInHierarchy(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { + if (useCaches(place)) { + return getInnersHierarchyCache().processMembers(processor, state, place) + } + else { + return processInnersInHierarchyNoCache(processor, state, place) + } +} + +fun GrTypeDefinition.processInnersInOuters(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { + if (useCaches(place)) { + return getInnersOutersCache().processMembers(processor, state, place) + } + else { + return processInnersInOutersNoCache(processor, state, place) + } +} + +internal fun GrTypeDefinition.processInnersInHierarchyNoCache(processor: PsiScopeProcessor, + state: ResolveState, + place: PsiElement): Boolean { + if (!doProcessInnersInClassAndInterfaces(processor, state, place)) return false + + var superClass: PsiClass? = GrClassImplUtil.getSuperClass(this, getExtendsListTypes(false)) + while (superClass != null) { + if (!superClass.doProcessInnerClasses(processor, state)) return false + if (!superClass.doProcessInterfaces(processor, state, place)) return false + superClass = superClass.superClass + } + return true +} + +private fun GrTypeDefinition.doProcessInnersInClassAndInterfaces(processor: PsiScopeProcessor, + state: ResolveState, + place: PsiElement): Boolean { + return doProcessOwnInnerClasses(processor, state) && + doProcessOwnInterfaces(processor, state, place) +} + +private fun GrTypeDefinition.doProcessOwnInterfaces(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { + for (anInterface in GrClassImplUtil.getInterfaces(this, false)) { + if (!anInterface.processDeclarations(processor, state, null, place)) return false + } + return true +} + +private fun GrTypeDefinition.doProcessOwnInnerClasses(processor: PsiScopeProcessor, state: ResolveState): Boolean { + val name = processor.getName(state) + if (name == null) { + for (inner in codeInnerClasses) { + if (!processor.execute(inner, state)) return false + } + } + else { + for (inner in codeInnerClasses) { + if (inner.name != name) continue + if (!processor.execute(inner, state)) return false + } + } + return true +} + +private fun PsiClass.doProcessInnerClasses(processor: PsiScopeProcessor, state: ResolveState): Boolean { + val name = processor.getName(state) + if (name == null) { + for (inner in innerClasses) { + if (!processor.execute(inner, state)) return false + } + } + else { + val inner = findInnerClassByName(name, false) + if (inner != null) { + if (!processor.execute(inner, state)) return false + } + } + return true +} + + +private fun PsiClass.doProcessInterfaces(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { + for (anInterface in interfaces) { + if (!anInterface.processDeclarations(processor, state, null, place)) return false + } + return true +} + +internal fun GrTypeDefinition.processInnersInOutersNoCache(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { + val outers = collectOuterClasses().reversed() + for (outer in outers) { + if (!outer.doProcessInnersInClassAndInterfaces(processor, state, place)) return false + } + return true +} + +private fun GrTypeDefinition.collectOuterClasses(): List { + val result = SmartList() + var current: GrTypeDefinition? = containingClass as? GrTypeDefinition + while (current != null) { + result += current + current = current.containingClass as? GrTypeDefinition + } + return result +} + +private fun useCaches(place: PsiElement): Boolean { + if (place.parent is GrAnnotation) return false + if (ApplicationManager.getApplication().isDispatchThread) return false + val containingFile = place.containingFile + if (containingFile.originalFile !== containingFile) return false + return containingFile.getUserData(PsiFileEx.BATCH_REFERENCE_PROCESSING) == true +} From 1f818b95c02d1caf74660dfe2a760a98d706013f Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Thu, 16 Nov 2017 21:28:13 +0300 Subject: [PATCH 35/43] [groovy] pull getPackageName() into GroovyFileBase --- .../plugins/groovy/lang/psi/GroovyFile.java | 20 +------------------ .../groovy/lang/psi/GroovyFileBase.java | 20 +++++-------------- 2 files changed, 6 insertions(+), 34 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GroovyFile.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GroovyFile.java index ad0340897556..39d55e807d61 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GroovyFile.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GroovyFile.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2014 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.psi; import com.intellij.psi.PsiType; @@ -30,10 +16,6 @@ public interface GroovyFile extends GroovyFileBase { GrImportStatement[] getImportStatements(); - @Override - @NotNull - String getPackageName(); - @Nullable GrPackageDefinition getPackageDefinition(); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GroovyFileBase.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GroovyFileBase.java index d4719f3aa187..4eaef904f1bf 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GroovyFileBase.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/GroovyFileBase.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.psi; @@ -49,6 +35,10 @@ public interface GroovyFileBase extends PsiFile, GrVariableDeclarationOwner, GrS "java.math.BigDecimal", }; + @Override + @NotNull + String getPackageName(); + @NotNull GrTypeDefinition[] getTypeDefinitions(); From ee7a2a908109a4a5b593cb9c40f227bd41d45d95 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Thu, 16 Nov 2017 21:36:24 +0300 Subject: [PATCH 36/43] [groovy] update imports - make imports work with GroovyFileBase; - rename resolve() to resolveImport(). --- .../groovy/lang/resolve/GrCodeReferenceResolver.kt | 4 ++-- .../jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt | 6 +++--- .../groovy/lang/resolve/imports/GroovyFileImports.kt | 5 +++-- .../plugins/groovy/lang/resolve/imports/GroovyImport.kt | 6 +++--- .../plugins/groovy/lang/resolve/imports/RegularImport.kt | 8 ++++---- .../plugins/groovy/lang/resolve/imports/StarImport.kt | 8 ++++---- .../plugins/groovy/lang/resolve/imports/StaticImport.kt | 6 +++--- .../groovy/lang/resolve/imports/StaticStarImport.kt | 6 +++--- .../lang/resolve/imports/impl/GroovyFileImportsImpl.kt | 8 ++++---- .../lang/resolve/imports/impl/GroovyImportCollector.kt | 4 ++-- .../groovy/lang/resolve/imports/impl/NonFqnImport.kt | 4 ++-- 11 files changed, 33 insertions(+), 32 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt index aa13f05d2b90..a467fd4c9eaf 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt @@ -74,7 +74,7 @@ private fun GrCodeReferenceElement.resolveAsImportReference(): Collection { - val resolved = import.resolve(file) ?: return emptyList() + val resolved = import.resolveImport(file) ?: return emptyList() return listOf(ElementGroovyResult(resolved)) } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt index 7a284efd594c..a1ced15c8563 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt @@ -11,7 +11,7 @@ import com.intellij.psi.scope.NameHint import com.intellij.psi.scope.PsiScopeProcessor import com.intellij.psi.util.CachedValueProvider.Result import com.intellij.psi.util.CachedValuesManager.getCachedValue -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.DefaultConstructor import org.jetbrains.plugins.groovy.lang.resolve.processors.DynamicMembersHint @@ -76,7 +76,7 @@ fun getDefaultConstructor(clazz: PsiClass): PsiMethod { } } -fun GroovyFile.processClassesInFile(processor: PsiScopeProcessor, state: ResolveState): Boolean { +fun GroovyFileBase.processClassesInFile(processor: PsiScopeProcessor, state: ResolveState): Boolean { if (!processor.shouldProcessClasses()) return true val scriptClass = scriptClass if (scriptClass != null && !ResolveUtil.processElement(processor, scriptClass, state)) return false @@ -86,7 +86,7 @@ fun GroovyFile.processClassesInFile(processor: PsiScopeProcessor, state: Resolve return true } -fun GroovyFile.processClassesInPackage(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement = this): Boolean { +fun GroovyFileBase.processClassesInPackage(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement = this): Boolean { if (!processor.shouldProcessClasses()) return true val aPackage = JavaPsiFacade.getInstance(project).findPackage(packageName) ?: return true return aPackage.processDeclarations(PackageSkippingProcessor(processor), state, null, place) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyFileImports.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyFileImports.kt index d9b4461dcf14..9e2f54a8f5a9 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyFileImports.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyFileImports.kt @@ -4,12 +4,13 @@ package org.jetbrains.plugins.groovy.lang.resolve.imports import com.intellij.psi.PsiElement import com.intellij.psi.ResolveState import com.intellij.psi.scope.PsiScopeProcessor -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement interface GroovyFileImports { - val file: GroovyFile + val file: GroovyFileBase + val starImports: Collection diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyImport.kt index b806d3d8f5fd..0fc760dc7a90 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyImport.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyImport.kt @@ -4,19 +4,19 @@ package org.jetbrains.plugins.groovy.lang.resolve.imports import com.intellij.psi.PsiElement import com.intellij.psi.ResolveState import com.intellij.psi.scope.PsiScopeProcessor -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase interface GroovyImport { /** * Resolves current import using [file] as a context */ - fun resolve(file: GroovyFile): PsiElement? + fun resolveImport(file: GroovyFileBase): PsiElement? /** * Feeds the processor with elements available via this import */ - fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFile): Boolean + fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFileBase): Boolean /** * Checks whether this import could be removed wihout any changes in resolve. diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt index ce0d005eb40e..7acf91608263 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt @@ -8,7 +8,7 @@ import com.intellij.psi.PsiClass import com.intellij.psi.PsiElement import com.intellij.psi.ResolveState import com.intellij.psi.scope.PsiScopeProcessor -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase import org.jetbrains.plugins.groovy.lang.resolve.checkName import org.jetbrains.plugins.groovy.lang.resolve.processClassesInFile import org.jetbrains.plugins.groovy.lang.resolve.processClassesInPackage @@ -34,17 +34,17 @@ data class RegularImport(val classFqn: String, override val name: String) : Groo override val isAliased: Boolean = getShortName(classFqn) != name - override fun resolve(file: GroovyFile): PsiClass? { + override fun resolveImport(file: GroovyFileBase): PsiClass? { if (!file.packageName.isEmpty() && '.' !in classFqn) return null val facade = JavaPsiFacade.getInstance(file.project) return facade.findClass(classFqn, file.resolveScope) } - override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFile): Boolean { + override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFileBase): Boolean { if (!processor.shouldProcessClasses()) return true if (!processor.checkName(name, state)) return true - val clazz = resolve(file) ?: return true + val clazz = resolveImport(file) ?: return true return processor.execute(clazz, state.put(importedNameKey, name)) } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StarImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StarImport.kt index 56df8678383f..3a5bf79605be 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StarImport.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StarImport.kt @@ -6,19 +6,19 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiPackage import com.intellij.psi.ResolveState import com.intellij.psi.scope.PsiScopeProcessor -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase data class StarImport(val packageFqn: String) : GroovyStarImport { override val fqn: String get() = packageFqn - override fun resolve(file: GroovyFile): PsiPackage? { + override fun resolveImport(file: GroovyFileBase): PsiPackage? { val facade = JavaPsiFacade.getInstance(file.project) return facade.findPackage(packageFqn) } - override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFile): Boolean { - val pckg = resolve(file) ?: return true + override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFileBase): Boolean { + val pckg = resolveImport(file) ?: return true return pckg.processDeclarations(processor, state, null, place) } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt index 8eeb22a44b30..a58ef2f5cbfe 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt @@ -4,7 +4,7 @@ package org.jetbrains.plugins.groovy.lang.resolve.imports import com.intellij.psi.PsiElement import com.intellij.psi.ResolveState import com.intellij.psi.scope.PsiScopeProcessor -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils.* import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.NonFqnImport @@ -37,9 +37,9 @@ data class StaticImport constructor( override val isAliased: Boolean = memberName != name - override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFile): Boolean { + override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFileBase): Boolean { if (!processor.shouldProcessMembers()) return true - val clazz = resolve(file) ?: return true + val clazz = resolveImport(file) ?: return true val namesMapping = namesMapping() for (each in GroovyResolverProcessor.allProcessors(processor)) { val hintName = ResolveUtil.getNameHint(each) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticStarImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticStarImport.kt index b03e81aaf1a2..6118b3d4f290 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticStarImport.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticStarImport.kt @@ -6,7 +6,7 @@ package org.jetbrains.plugins.groovy.lang.resolve.imports import com.intellij.psi.PsiElement import com.intellij.psi.ResolveState import com.intellij.psi.scope.PsiScopeProcessor -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.NonFqnImport import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolverProcessor import org.jetbrains.plugins.groovy.lang.resolve.processors.StaticMembersFilteringProcessor @@ -15,8 +15,8 @@ data class StaticStarImport(override val classFqn: String) : NonFqnImport(), Gro override val fqn: String get() = classFqn - override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFile): Boolean { - val clazz = resolve(file) ?: return true + override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFileBase): Boolean { + val clazz = resolveImport(file) ?: return true for (each in GroovyResolverProcessor.allProcessors(processor)) { val filteringProcessor = StaticMembersFilteringProcessor(each, null) if (!clazz.processDeclarations(filteringProcessor, state, null, place)) return false diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyFileImportsImpl.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyFileImportsImpl.kt index 74b5691a7600..8f7447c3ec36 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyFileImportsImpl.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyFileImportsImpl.kt @@ -6,7 +6,7 @@ package org.jetbrains.plugins.groovy.lang.resolve.imports.impl import com.intellij.psi.PsiElement import com.intellij.psi.ResolveState import com.intellij.psi.scope.PsiScopeProcessor -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyFileImports import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImport @@ -15,7 +15,7 @@ import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint import org.jetbrains.plugins.groovy.util.flatten internal class GroovyFileImportsImpl( - override val file: GroovyFile, + override val file: GroovyFileBase, private val imports: Map, Collection>, private val statementToImport: Map, private val importToStatement: Map @@ -74,7 +74,7 @@ internal class GroovyFileImportsImpl( for (import in starImports) { val statement = importToStatement[import] ?: continue - if (import.resolve(file) == null) { + if (import.resolveImport(file) == null) { result += statement } } @@ -82,7 +82,7 @@ internal class GroovyFileImportsImpl( for (import in allNamedImports) { if (import.name !in names) continue val statement = importToStatement[import] ?: continue - if (import.resolve(file) == null) { + if (import.resolveImport(file) == null) { result += statement } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyImportCollector.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyImportCollector.kt index e3f0f5371541..35c99d0fcb89 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyImportCollector.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyImportCollector.kt @@ -4,13 +4,13 @@ package org.jetbrains.plugins.groovy.lang.resolve.imports.impl import com.intellij.openapi.util.text.StringUtil.getPackageName import com.intellij.openapi.util.text.StringUtil.getShortName import com.intellij.util.reverse -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement import org.jetbrains.plugins.groovy.lang.resolve.Import import org.jetbrains.plugins.groovy.lang.resolve.ImportType import org.jetbrains.plugins.groovy.lang.resolve.imports.* -class GroovyImportCollector(private val file: GroovyFile) { +class GroovyImportCollector(private val file: GroovyFileBase) { private val statementToImport = mutableMapOf() private val imports = HashMap, LinkedHashMap>() diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/NonFqnImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/NonFqnImport.kt index ad9c69b13ed7..d6baf5a17a53 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/NonFqnImport.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/NonFqnImport.kt @@ -4,14 +4,14 @@ package org.jetbrains.plugins.groovy.lang.resolve.imports.impl import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.JavaPsiFacade import com.intellij.psi.PsiClass -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImport abstract class NonFqnImport : GroovyImport { abstract val classFqn: String - override fun resolve(file: GroovyFile): PsiClass? { + override fun resolveImport(file: GroovyFileBase): PsiClass? { val facade = JavaPsiFacade.getInstance(file.project) val scope = file.resolveScope From 941f470e13cafb11ba2a52b90ce70ba0080acf19 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 17 Nov 2017 15:17:11 +0300 Subject: [PATCH 37/43] [groovy] pull up file-level declarations logic to GroovyFileBaseImpl --- .../lang/psi/impl/GroovyFileBaseImpl.java | 37 +++++++++++-------- .../groovy/lang/psi/impl/GroovyFileImpl.java | 10 +---- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileBaseImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileBaseImpl.java index a8782efe0a17..b6082192b0d6 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileBaseImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileBaseImpl.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.psi.impl; @@ -22,6 +8,8 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.psi.FileViewProvider; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; +import com.intellij.psi.ResolveState; +import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.stubs.StubElement; import com.intellij.psi.tree.IFileElementType; import com.intellij.reference.SoftReference; @@ -45,6 +33,10 @@ import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.GrTopStatement; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.ControlFlowBuilder; +import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyFileImports; + +import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.processClassesInFile; +import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.processClassesInPackage; /** * @author ilyas @@ -204,4 +196,19 @@ public abstract class GroovyFileBaseImpl extends PsiFileBase implements GroovyFi super.deleteChildRange(first, last); } + @Override + public boolean processDeclarations(@NotNull PsiScopeProcessor processor, + @NotNull ResolveState state, + @Nullable PsiElement lastParent, + @NotNull PsiElement place) { + final GroovyFileImports imports = getImports(); + if (!processClassesInFile(this, processor, state)) return false; + if (!imports.processAllNamedImports(processor, state, place)) return false; + if (!processClassesInPackage(this, processor, state, place)) return false; + if (!imports.processAllStarImports(processor, state, place)) return false; + if (!imports.processDefaultImports(processor, state, place)) return false; + return true; + } + + protected abstract GroovyFileImports getImports(); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java index 4bdfe661a096..7ba56938adfb 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java @@ -49,9 +49,6 @@ import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolverProces import java.util.concurrent.ConcurrentMap; -import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.processClassesInFile; -import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.processClassesInPackage; - /** * Implements all abstractions related to Groovy file * @@ -187,12 +184,7 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile, Ps if (!ResolveUtil.processClassDeclarations(scriptClass, processor, state, lastParent, place)) return false; } - final GroovyFileImports imports = getImports(); - if (!processClassesInFile(this, processor, state)) return false; - if (!imports.processAllNamedImports(processor, state, place)) return false; - if (!processClassesInPackage(this, processor, state, place)) return false; - if (!imports.processAllStarImports(processor, state, place)) return false; - if (!imports.processDefaultImports(processor, state, place)) return false; + if (!super.processDeclarations(processor, state, lastParent, place)) return false; if (ResolveUtil.shouldProcessProperties(classHint)) { if (!processChildrenScopes(processor, state, lastParent, place)) return false; From 75d2dfb6ccaa0d1aad76e6b04e3db3be5fa429b1 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 17 Nov 2017 15:42:50 +0300 Subject: [PATCH 38/43] [groovy] rename MembersCache to DeclarationHolder --- .../caches/{MembersCache.kt => DeclarationHolder.kt} | 4 ++-- .../groovy/lang/resolve/caches/innersCache.kt | 12 ++++++------ .../jetbrains/plugins/groovy/lang/resolve/inners.kt | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) rename plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/{MembersCache.kt => DeclarationHolder.kt} (70%) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/MembersCache.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/DeclarationHolder.kt similarity index 70% rename from plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/MembersCache.kt rename to plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/DeclarationHolder.kt index c1e790bd8e27..c15431990060 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/MembersCache.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/DeclarationHolder.kt @@ -5,7 +5,7 @@ import com.intellij.psi.PsiElement import com.intellij.psi.ResolveState import com.intellij.psi.scope.PsiScopeProcessor -interface MembersCache { +interface DeclarationHolder { - fun processMembers(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean + fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/innersCache.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/innersCache.kt index 18bfb01bcad6..60a8420d3349 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/innersCache.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/innersCache.kt @@ -16,13 +16,13 @@ import org.jetbrains.plugins.groovy.lang.resolve.processInnersInOutersNoCache import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint import org.jetbrains.plugins.groovy.lang.resolve.processors.GrScopeProcessorWithHints -fun GrTypeDefinition.getInnersHierarchyCache(): MembersCache { +fun GrTypeDefinition.getInnersHierarchyCache(): DeclarationHolder { return CachedValuesManager.getCachedValue(this) { makeResult(buildCache(this::processInnersInHierarchyNoCache)) } } -fun GrTypeDefinition.getInnersOutersCache(): MembersCache { +fun GrTypeDefinition.getInnersOutersCache(): DeclarationHolder { return CachedValuesManager.getCachedValue(this) { makeResult(buildCache(this::processInnersInOutersNoCache)) } @@ -34,7 +34,7 @@ private fun GrTypeDefinition.makeResult(value: T): Result { private typealias ProcessFunction = (PsiScopeProcessor, ResolveState, PsiElement) -> Boolean -private inline fun GrTypeDefinition.buildCache(f: ProcessFunction): MembersCache { +private inline fun GrTypeDefinition.buildCache(f: ProcessFunction): DeclarationHolder { val processor = ClassCacheBuilderProcessor() f(processor, ResolveState.initial(), this) return processor.buildCache() @@ -44,7 +44,7 @@ private class ClassCacheBuilderProcessor : GrScopeProcessorWithHints(null, Class private val classMap = HashMap() - internal fun buildCache(): MembersCache = ClassCacheImpl(classMap) + internal fun buildCache(): DeclarationHolder = ClassCache(classMap) override fun execute(element: PsiElement, state: ResolveState): Boolean { val clazz = element as? PsiClass ?: return true @@ -59,9 +59,9 @@ private class ClassCacheBuilderProcessor : GrScopeProcessorWithHints(null, Class } } -private class ClassCacheImpl(private val classMap: Map) : MembersCache { +private class ClassCache(private val classMap: Map) : DeclarationHolder { - override fun processMembers(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { + override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { if (classMap.isEmpty()) return true val name = processor.getName(state) if (name == null) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/inners.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/inners.kt index 1ee615c09f4c..59f46bb1ac96 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/inners.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/inners.kt @@ -18,7 +18,7 @@ import org.jetbrains.plugins.groovy.lang.resolve.caches.getInnersOutersCache fun GrTypeDefinition.processInnerInHierarchy(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { if (useCaches(place)) { - return getInnersHierarchyCache().processMembers(processor, state, place) + return getInnersHierarchyCache().processDeclarations(processor, state, place) } else { return processInnersInHierarchyNoCache(processor, state, place) @@ -27,7 +27,7 @@ fun GrTypeDefinition.processInnerInHierarchy(processor: PsiScopeProcessor, state fun GrTypeDefinition.processInnersInOuters(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { if (useCaches(place)) { - return getInnersOutersCache().processMembers(processor, state, place) + return getInnersOutersCache().processDeclarations(processor, state, place) } else { return processInnersInOutersNoCache(processor, state, place) From cf0990eae09d5a8606398527cdcdd35a033a0b40 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 17 Nov 2017 20:04:49 +0300 Subject: [PATCH 39/43] [groovy] add and use AnnotationHint Make processor responsible for answering the question "are we resolving an annotation now?" --- .../groovy/lang/psi/util/GrClassImplUtil.java | 10 ++-------- .../groovy/lang/resolve/AnnotationHint.java | 11 +++++++++++ .../lang/resolve/GrCodeReferenceResolver.kt | 2 +- .../plugins/groovy/lang/resolve/ResolveUtil.kt | 10 ++++++++++ .../lang/resolve/processors/ClassProcessor.kt | 15 +++++++++++++-- 5 files changed, 37 insertions(+), 11 deletions(-) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/AnnotationHint.java diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java index 84ab8e7729c0..ef1dddf0d08e 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java @@ -23,7 +23,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyLanguage; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList; -import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrEnumConstantInitializer; @@ -33,7 +32,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAc import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrReflectedMethod; -import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.typedef.GrTypeDefinitionImpl; @@ -43,6 +41,7 @@ import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import java.util.*; +import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.isAnnotationResolve; import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.shouldProcessTypeParameters; /** @@ -198,12 +197,7 @@ public class GrClassImplUtil { @NotNull ResolveState state, @Nullable PsiElement lastParent, @NotNull PsiElement place) { - if (place instanceof GrCodeReferenceElement) { - final PsiElement possibleAnnotation = PsiTreeUtil.skipParentsOfType(place, GrCodeReferenceElement.class); - if (possibleAnnotation instanceof GrAnnotation) { - return true; //don't process class members while resolving annotation - } - } + if (isAnnotationResolve(processor)) return true; //don't process class members while resolving annotation if (shouldProcessTypeParameters(processor)) { for (final PsiTypeParameter typeParameter : grType.getTypeParameters()) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/AnnotationHint.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/AnnotationHint.java new file mode 100644 index 000000000000..a5138eff8644 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/AnnotationHint.java @@ -0,0 +1,11 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve; + +import com.intellij.openapi.util.Key; + +public interface AnnotationHint { + + Key HINT_KEY = Key.create("groovy.annotation.resolve"); + + boolean isAnnotationResolve(); +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt index a467fd4c9eaf..ded23c3e2224 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt @@ -114,7 +114,7 @@ private fun GrCodeReferenceElement.resolveReference(): Collection = PsiType.EMPTY_ARRAY -) : GrScopeProcessorWithHints(name, RESOLVE_KINDS_CLASS), GrResolverProcessor { + private val typeArguments: Array = PsiType.EMPTY_ARRAY, + private val annotationResolve: Boolean = false +) : GrScopeProcessorWithHints(name, RESOLVE_KINDS_CLASS), AnnotationHint, GrResolverProcessor { private val myResults = SmartList() override val results: List get() = myResults @@ -29,4 +32,12 @@ class ClassProcessor( ) return false } + + @Suppress("UNCHECKED_CAST") + override fun getHint(hintKey: Key): T? { + if (hintKey == AnnotationHint.HINT_KEY) return this as T + return super.getHint(hintKey) + } + + override fun isAnnotationResolve(): Boolean = annotationResolve } From 7bd43d37bfb2496eda97becd59002117ad163c57 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 17 Nov 2017 20:09:55 +0300 Subject: [PATCH 40/43] [platform] add ResolveState#putAll(ResolveState) --- .../src/com/intellij/psi/ResolveState.java | 90 ++++++++++++++----- 1 file changed, 67 insertions(+), 23 deletions(-) diff --git a/platform/core-api/src/com/intellij/psi/ResolveState.java b/platform/core-api/src/com/intellij/psi/ResolveState.java index 4514cc57c722..879d1c850d12 100644 --- a/platform/core-api/src/com/intellij/psi/ResolveState.java +++ b/platform/core-api/src/com/intellij/psi/ResolveState.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2014 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. /* * @author max @@ -26,7 +12,7 @@ import org.jetbrains.annotations.NotNull; import java.util.Map; -@SuppressWarnings({"unchecked", "ConstantConditions"}) +@SuppressWarnings({"unchecked"}) public class ResolveState { private static final ResolveState ourInitialState = new ResolveState(); @@ -40,6 +26,11 @@ public class ResolveState { return new OneElementResolveState(key, value); } + @NotNull + public ResolveState putAll(@NotNull ResolveState state) { + return state; + } + public T get(@NotNull Key key) { if (key instanceof KeyWithDefaultValue) { return ((KeyWithDefaultValue)key).getDefaultValue(); @@ -67,6 +58,12 @@ public class ResolveState { return new TwoElementResolveState(myKey, myValue, key, value); } + @NotNull + @Override + public ResolveState putAll(@NotNull ResolveState state) { + return state.get(myKey) == null ? state.put(myKey, myValue) : state; + } + @Override public T get(@NotNull Key key) { Object value = myKey.equals(key) ? myValue : null; @@ -103,6 +100,31 @@ public class ResolveState { return new ManyElementResolveState(this, key, value); } + @NotNull + @Override + public ResolveState putAll(@NotNull ResolveState state) { + if (state == ourInitialState) { + return this; + } + else if (state instanceof OneElementResolveState) { + OneElementResolveState oneState = (OneElementResolveState)state; + return put(oneState.myKey, oneState.myValue); + } + boolean has1 = state.get(myKey1) != null; + boolean has2 = state.get(myKey2) != null; + if (has1 && has2) { + return state; + } + else if (has1) { + return state.put(myKey2, myValue2); + } + else if (has2) { + return state.put(myKey1, myValue1); + } + // at this point our keys are not in other and other has at least 2 keys + return new ManyElementResolveState(state, this); + } + @Override public T get(@NotNull Key key) { Object value; @@ -126,15 +148,30 @@ public class ResolveState { private static class ManyElementResolveState extends ResolveState { private final Map myValues = new THashMap<>(); - ManyElementResolveState(@NotNull ManyElementResolveState parent, @NotNull Key key, Object value) { - myValues.putAll(parent.myValues); + ManyElementResolveState(@NotNull ResolveState state1, @NotNull ResolveState state2) { + putAllNoCopy(state1); + putAllNoCopy(state2); + } + + ManyElementResolveState(@NotNull ResolveState state, @NotNull Key key, Object value) { + putAllNoCopy(state); myValues.put(key, value); } - ManyElementResolveState(@NotNull TwoElementResolveState twoState, @NotNull Key key, Object value) { - myValues.put(twoState.myKey1, twoState.myValue1); - myValues.put(twoState.myKey2, twoState.myValue2); - myValues.put(key, value); + private void putAllNoCopy(@NotNull ResolveState other) { + if (other instanceof OneElementResolveState) { + OneElementResolveState oneState = (OneElementResolveState)other; + myValues.put(oneState.myKey, oneState.myValue); + } + else if (other instanceof TwoElementResolveState) { + TwoElementResolveState twoState = (TwoElementResolveState)other; + myValues.put(twoState.myKey1, twoState.myValue1); + myValues.put(twoState.myKey2, twoState.myValue2); + } + else if (other instanceof ManyElementResolveState) { + ManyElementResolveState manyState = (ManyElementResolveState)other; + myValues.putAll(manyState.myValues); + } } @NotNull @@ -143,11 +180,18 @@ public class ResolveState { return new ManyElementResolveState(this, key, value); } + @NotNull + @Override + public ResolveState putAll(@NotNull ResolveState state) { + if (state == ourInitialState) return this; + return new ManyElementResolveState(this, state); + } + @Override public T get(@NotNull Key key) { final T value = (T)myValues.get(key); if (value == null && key instanceof KeyWithDefaultValue) { - return ((KeyWithDefaultValue) key).getDefaultValue(); + return ((KeyWithDefaultValue)key).getDefaultValue(); } return value; } From 4489994918cff48648221aa1961fe04ce5432546 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 17 Nov 2017 20:35:34 +0300 Subject: [PATCH 41/43] [groovy] add file declaration caches Add annotation cache, pull up file declaration cache to GroovyFileBaseImpl --- .../lang/psi/impl/GroovyFileBaseImpl.java | 51 +++++++++++++- .../groovy/lang/psi/impl/GroovyFileImpl.java | 66 ++----------------- .../groovy/lang/resolve/caches/fileCache.kt | 56 ++++++++++++++++ 3 files changed, 109 insertions(+), 64 deletions(-) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/fileCache.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileBaseImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileBaseImpl.java index b6082192b0d6..2f41644e94a8 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileBaseImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileBaseImpl.java @@ -4,14 +4,20 @@ package org.jetbrains.plugins.groovy.lang.psi.impl; import com.intellij.extapi.psi.PsiFileBase; import com.intellij.lang.Language; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.fileTypes.FileType; import com.intellij.psi.FileViewProvider; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.ResolveState; +import com.intellij.psi.impl.PsiFileEx; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.stubs.StubElement; import com.intellij.psi.tree.IFileElementType; +import com.intellij.psi.util.CachedValue; +import com.intellij.psi.util.CachedValueProvider.Result; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.PsiModificationTracker; import com.intellij.reference.SoftReference; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; @@ -33,18 +39,29 @@ import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.GrTopStatement; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.ControlFlowBuilder; +import org.jetbrains.plugins.groovy.lang.resolve.caches.DeclarationHolder; +import org.jetbrains.plugins.groovy.lang.resolve.caches.FileCacheBuilderProcessor; import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyFileImports; -import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.processClassesInFile; -import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.processClassesInPackage; +import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.*; /** * @author ilyas */ public abstract class GroovyFileBaseImpl extends PsiFileBase implements GroovyFileBase, GrControlFlowOwner { + private final CachedValue myAnnotationsCache; + private final CachedValue myDeclarationsCache; + protected GroovyFileBaseImpl(FileViewProvider viewProvider, @NotNull Language language) { super(viewProvider, language); + CachedValuesManager cachedValuesManager = CachedValuesManager.getManager(viewProvider.getManager().getProject()); + myAnnotationsCache = cachedValuesManager.createCachedValue(() -> Result.create( + buildCache(true), this, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT + ), false); + myDeclarationsCache = cachedValuesManager.createCachedValue(() -> Result.create( + buildCache(false), this, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT + ), false); } public GroovyFileBaseImpl(IFileElementType root, IFileElementType root1, FileViewProvider provider) { @@ -201,6 +218,36 @@ public abstract class GroovyFileBaseImpl extends PsiFileBase implements GroovyFi @NotNull ResolveState state, @Nullable PsiElement lastParent, @NotNull PsiElement place) { + return getAppropriateHolder(processor).processDeclarations(processor, state, place); + } + + @NotNull + private DeclarationHolder getAppropriateHolder(@NotNull PsiScopeProcessor processor) { + if (isAnnotationResolve(processor)) { + return myAnnotationsCache.getValue(); + } + else if (useCache()) { + return myDeclarationsCache.getValue(); + } + else { + return this::processDeclarationsNoCache; + } + } + + private boolean useCache() { + if (!isPhysical()) return false; + if (ApplicationManager.getApplication().isDispatchThread()) return false; + return getUserData(PsiFileEx.BATCH_REFERENCE_PROCESSING) == Boolean.TRUE; + } + + @NotNull + private DeclarationHolder buildCache(boolean annotationCache) { + FileCacheBuilderProcessor processor = new FileCacheBuilderProcessor(annotationCache); + processDeclarationsNoCache(processor, ResolveState.initial(), this); + return processor.buildCache(); + } + + private boolean processDeclarationsNoCache(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, @NotNull PsiElement place) { final GroovyFileImports imports = getImports(); if (!processClassesInFile(this, processor, state)) return false; if (!imports.processAllNamedImports(processor, state, place)) return false; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java index 7ba56938adfb..9543c6477bd5 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java @@ -6,18 +6,16 @@ import com.intellij.lang.ASTNode; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; -import com.intellij.psi.impl.PsiFileEx; -import com.intellij.psi.impl.source.resolve.SymbolCollectingProcessor.ResultWithContext; -import com.intellij.psi.scope.BaseScopeProcessor; import com.intellij.psi.scope.ElementClassHint; import com.intellij.psi.scope.NameHint; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.stubs.StubElement; -import com.intellij.psi.util.*; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.PsiModificationTracker; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; -import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.MostlySingularMultiMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyLanguage; @@ -44,8 +42,6 @@ import org.jetbrains.plugins.groovy.lang.resolve.MethodTypeInferencer; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyFileImports; import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImports; -import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint; -import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolverProcessor; import java.util.concurrent.ConcurrentMap; @@ -69,12 +65,9 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile, Ps private volatile GroovyScriptClass myScriptClass; private volatile GrParameter mySyntheticArgsParameter; private volatile PsiElement myContext; - private final CachedValue> myResolveCache; public GroovyFileImpl(FileViewProvider viewProvider) { super(viewProvider, GroovyLanguage.INSTANCE); - myResolveCache = CachedValuesManager.getManager(myManager.getProject()).createCachedValue( - () -> CachedValueProvider.Result.create(buildDeclarationCache(), PsiModificationTracker.MODIFICATION_COUNT, this), false); } @Override @@ -119,57 +112,6 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile, Ps @NotNull ResolveState state, @Nullable PsiElement lastParent, @NotNull PsiElement place) { - - if (isPhysical() && !isScript() && - !ApplicationManager.getApplication().isDispatchThread() && - (getUserData(PsiFileEx.BATCH_REFERENCE_PROCESSING) == Boolean.TRUE || myResolveCache.hasUpToDateValue())) { - return processCachedDeclarations(processor, state, myResolveCache.getValue()); - } - - return processDeclarationsNoGuess(processor, state, lastParent, place); - } - - private static boolean processCachedDeclarations(@NotNull PsiScopeProcessor processor, - @NotNull ResolveState state, - MostlySingularMultiMap cache) { - for (PsiScopeProcessor each : GroovyResolverProcessor.allProcessors(processor)) { - String name = ResolveUtil.getNameHint(each); - Processor cacheProcessor = res -> each.execute( - res.getElement(), state.put(ClassHint.RESOLVE_CONTEXT, res.getFileContext()) - ); - boolean result = name != null ? cache.processForKey(name, cacheProcessor) : cache.processAllValues(cacheProcessor); - if (!result) return false; - } - return true; - } - - @NotNull - private MostlySingularMultiMap buildDeclarationCache() { - MostlySingularMultiMap results = new MostlySingularMultiMap<>(); - processDeclarationsNoGuess(new BaseScopeProcessor() { - @Override - public boolean execute(@NotNull PsiElement element, @NotNull ResolveState state) { - if (element instanceof PsiNamedElement) { - PsiElement context = state.get(ClassHint.RESOLVE_CONTEXT); - String name = getDeclarationName((PsiNamedElement)element, context); - if (name != null) { - results.add(name, new ResultWithContext((PsiNamedElement)element, context)); - } - } - return true; - } - - private String getDeclarationName(@NotNull PsiNamedElement element, @Nullable PsiElement context) { - String name = context instanceof GrImportStatement ? ((GrImportStatement)context).getImportedName() : null; - return name != null ? name : element.getName(); - } - }, ResolveState.initial(), null, this); - return results; - } - - private boolean processDeclarationsNoGuess(@NotNull PsiScopeProcessor processor, - @NotNull ResolveState state, - @Nullable PsiElement lastParent, @NotNull PsiElement place) { ElementClassHint classHint = processor.getHint(ElementClassHint.KEY); if (myContext != null) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/fileCache.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/fileCache.kt new file mode 100644 index 000000000000..8e43bb4a04f7 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/fileCache.kt @@ -0,0 +1,56 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve.caches + +import com.intellij.openapi.util.Key +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiNamedElement +import com.intellij.psi.ResolveState +import com.intellij.psi.scope.BaseScopeProcessor +import com.intellij.psi.scope.ElementClassHint +import com.intellij.psi.scope.PsiScopeProcessor +import com.intellij.util.containers.MostlySingularMultiMap +import org.jetbrains.plugins.groovy.lang.resolve.AnnotationHint +import org.jetbrains.plugins.groovy.lang.resolve.getName +import org.jetbrains.plugins.groovy.lang.resolve.imports.importedNameKey + +private data class ElementWithState(val element: PsiElement, val state: ResolveState) + +class FileCacheBuilderProcessor(private val annotationResolve: Boolean) : BaseScopeProcessor(), ElementClassHint, AnnotationHint { + + private val declarations = MostlySingularMultiMap() + + fun buildCache(): DeclarationHolder = FileDeclarationsCache(declarations) + + override fun execute(element: PsiElement, state: ResolveState): Boolean { + val namedElement = element as? PsiNamedElement ?: return true + val name = state.get(importedNameKey) ?: namedElement.name ?: return true + declarations.add(name, ElementWithState(element, state)) + return true + } + + override fun getHint(hintKey: Key): T? { + @Suppress("UNCHECKED_CAST") + return when (hintKey) { + AnnotationHint.HINT_KEY, + ElementClassHint.KEY -> this as T + else -> null + } + } + + override fun isAnnotationResolve(): Boolean = annotationResolve + + override fun shouldProcess(kind: ElementClassHint.DeclarationKind?): Boolean { + return !annotationResolve || kind === ElementClassHint.DeclarationKind.CLASS + } +} + +private class FileDeclarationsCache(private val declarations: MostlySingularMultiMap) : DeclarationHolder { + + override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { + val declarationProcessor = { (element, cachedState): ElementWithState -> + processor.execute(element, state.putAll(cachedState)) + } + val name = processor.getName(state) + return if (name == null) declarations.processAllValues(declarationProcessor) else declarations.processForKey(name, declarationProcessor) + } +} From 75b3a13054c5903359844d3748869029e1aff74c Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Sat, 18 Nov 2017 20:36:45 +0300 Subject: [PATCH 42/43] [groovy] clean GrImportStatementImpl --- .../imports/GrImportStatementImpl.java | 183 +----------------- 1 file changed, 5 insertions(+), 178 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/toplevel/imports/GrImportStatementImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/toplevel/imports/GrImportStatementImpl.java index ef230ea2f0fe..6d80e87eeaac 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/toplevel/imports/GrImportStatementImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/toplevel/imports/GrImportStatementImpl.java @@ -3,12 +3,11 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.toplevel.imports; import com.intellij.lang.ASTNode; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.*; -import com.intellij.psi.scope.DelegatingScopeProcessor; -import com.intellij.psi.scope.ElementClassHint; -import com.intellij.psi.scope.NameHint; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.ResolveState; +import com.intellij.psi.StubBasedPsiElement; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.stubs.IStubElementType; import com.intellij.psi.util.CachedValueProvider; @@ -20,27 +19,15 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.impl.GrStubElementBase; import org.jetbrains.plugins.groovy.lang.psi.stubs.GrImportStatementStub; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; -import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImport; -import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint; -import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolverProcessor; -import org.jetbrains.plugins.groovy.lang.resolve.processors.StaticMembersFilteringProcessor; -import java.util.ArrayList; -import java.util.List; - -import static com.intellij.psi.scope.ElementClassHint.DeclarationKind.CLASS; -import static com.intellij.psi.scope.ElementClassHint.DeclarationKind.METHOD; -import static com.intellij.util.containers.ContainerUtil.zip; import static org.jetbrains.plugins.groovy.lang.psi.impl.utils.PsiImportUtil.createImportFromStatement; /** @@ -52,7 +39,7 @@ public class GrImportStatementImpl extends GrStubElementBase> namesMapping = namesMapping(importedName, refName); - for (PsiScopeProcessor each : GroovyResolverProcessor.allProcessors(processor)) { - final String hintName = ResolveUtil.getNameHint(each); - for (Pair names : namesMapping) { - if (hintName != null && !hintName.equals(names.first)) continue; - PsiScopeProcessor delegate = new StaticMembersFilteringProcessor(each, names.second); - if (!clazz.processDeclarations(delegate, state, lastParent, place)) return false; - } - } - - return true; - } - - private static Iterable> namesMapping(@NotNull String importedName, @NotNull String refName) { - if (importedName.equals(refName)) { - Iterable importedNames = names(importedName); - return zip(importedNames, importedNames); - } - else { - return zip(names(importedName), names(refName)); - } - } - - private static Iterable names(@NotNull String importedName) { - List result = new ArrayList<>(); - result.add(importedName); - result.add(GroovyPropertyUtils.getGetterNameNonBoolean(importedName)); - result.add(GroovyPropertyUtils.getGetterNameBoolean(importedName)); - result.add(GroovyPropertyUtils.getSetterName(importedName)); - return result; - } - - private boolean processSingleClassImport(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state) { - if (!ResolveUtil.shouldProcessClasses(processor.getHint(ElementClassHint.KEY))) return true; - - GrCodeReferenceElement ref = getImportReference(); - if (ref == null) return true; - - final PsiElement resolved = ref.resolve(); - if (!(resolved instanceof PsiClass)) { - return true; - } - - if (!isAliasedImport() && isFromSamePackage((PsiClass)resolved)) { - return true; //don't process classes from the same package because such import statements are ignored by compiler - } - - return processor.execute(resolved, state.put(ClassHint.RESOLVE_CONTEXT, this)); - } - - private boolean isFromSamePackage(@NotNull PsiClass resolved) { - final String qualifiedName = resolved.getQualifiedName(); - final String packageName = ((GroovyFile)getContainingFile()).getPackageName(); - final String assumed = packageName + '.' + resolved.getName(); - return !packageName.isEmpty() && assumed.equals(qualifiedName); - } - - private boolean processDeclarationsForMultipleElements(@NotNull final PsiScopeProcessor processor, - @Nullable PsiElement lastParent, - @NotNull PsiElement place, - @NotNull ResolveState state) { - GrCodeReferenceElement ref = getImportReference(); - if (ref == null) return true; - - if (isStatic()) { - final PsiElement resolved = ref.resolve(); - if (resolved instanceof PsiClass) { - state = state.put(ClassHint.RESOLVE_CONTEXT, this); - final PsiClass clazz = (PsiClass)resolved; - for (final PsiScopeProcessor each : GroovyResolverProcessor.allProcessors(processor)) { - if (!clazz.processDeclarations(new DelegatingScopeProcessor(each) { - @Override - public boolean execute(@NotNull PsiElement element, @NotNull ResolveState state) { - if (element instanceof PsiMember && ((PsiMember)element).hasModifierProperty(PsiModifier.STATIC)) { - return super.execute(element, state); - } - return true; - } - }, state, lastParent, place)) return false; - } - } - } - else { - if (ResolveUtil.shouldProcessClasses(processor.getHint(ElementClassHint.KEY))) { - String qName = PsiUtil.getQualifiedReferenceText(ref); - if (qName != null) { - PsiPackage aPackage = JavaPsiFacade.getInstance(getProject()).findPackage(qName); - if (aPackage != null && !((GroovyFile)getContainingFile()).getPackageName().equals(aPackage.getQualifiedName())) { - state = state.put(ClassHint.RESOLVE_CONTEXT, this); - if (!aPackage.processDeclarations(processor, state, lastParent, place)) return false; - } - } - } - } - return true; - } - @Override public GrCodeReferenceElement getImportReference() { GrImportStatementStub stub = getStub(); From 5c801dcfab006aa7af5d28e346cc92dc14f7d97b Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Mon, 20 Nov 2017 15:15:04 +0300 Subject: [PATCH 43/43] [groovy] don't include annotation cache in all other declarations cache --- .../lang/psi/impl/GroovyFileBaseImpl.java | 21 ++++++++++++++----- .../groovy/lang/resolve/AnnotationHint.java | 6 ++++++ .../groovy/lang/resolve/ResolveUtil.kt | 12 ++++++++++- .../lang/resolve/imports/RegularImport.kt | 6 ++---- .../groovy/lang/resolve/imports/StarImport.kt | 2 ++ .../lang/resolve/imports/StaticImport.kt | 2 ++ .../lang/resolve/imports/StaticStarImport.kt | 2 ++ .../lang/resolve/processors/ClassProcessor.kt | 2 +- 8 files changed, 42 insertions(+), 11 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileBaseImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileBaseImpl.java index 2f41644e94a8..193189b2d0fb 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileBaseImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileBaseImpl.java @@ -39,6 +39,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.GrTopStatement; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.ControlFlowBuilder; +import org.jetbrains.plugins.groovy.lang.resolve.AnnotationHint; import org.jetbrains.plugins.groovy.lang.resolve.caches.DeclarationHolder; import org.jetbrains.plugins.groovy.lang.resolve.caches.FileCacheBuilderProcessor; import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyFileImports; @@ -52,6 +53,7 @@ public abstract class GroovyFileBaseImpl extends PsiFileBase implements GroovyFi private final CachedValue myAnnotationsCache; private final CachedValue myDeclarationsCache; + private final DeclarationHolder myAllCachedDeclarations; protected GroovyFileBaseImpl(FileViewProvider viewProvider, @NotNull Language language) { super(viewProvider, language); @@ -62,6 +64,9 @@ public abstract class GroovyFileBaseImpl extends PsiFileBase implements GroovyFi myDeclarationsCache = cachedValuesManager.createCachedValue(() -> Result.create( buildCache(false), this, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT ), false); + myAllCachedDeclarations = (processor, state, place) -> + myAnnotationsCache.getValue().processDeclarations(processor, state, place) && + myDeclarationsCache.getValue().processDeclarations(processor, state, place); } public GroovyFileBaseImpl(IFileElementType root, IFileElementType root1, FileViewProvider provider) { @@ -223,14 +228,20 @@ public abstract class GroovyFileBaseImpl extends PsiFileBase implements GroovyFi @NotNull private DeclarationHolder getAppropriateHolder(@NotNull PsiScopeProcessor processor) { - if (isAnnotationResolve(processor)) { + AnnotationHint hint = getAnnotationHint(processor); + if (hint == null) { + if (useCache()) { + return myAllCachedDeclarations; + } + else { + return this::processDeclarationsNoCache; + } + } + else if (hint.isAnnotationResolve()) { return myAnnotationsCache.getValue(); } - else if (useCache()) { - return myDeclarationsCache.getValue(); - } else { - return this::processDeclarationsNoCache; + return myDeclarationsCache.getValue(); } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/AnnotationHint.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/AnnotationHint.java index a5138eff8644..c989fb59d15b 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/AnnotationHint.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/AnnotationHint.java @@ -7,5 +7,11 @@ public interface AnnotationHint { Key HINT_KEY = Key.create("groovy.annotation.resolve"); + /** + * @return {@code true} if this processor expects only classes that may be annotations or + * {@code false} if this processor expects all other declarations except classes that may be annotations + * @see ResolveUtilKt#isAnnotationResolve + * @see ResolveUtilKt#isNonAnnotationResolve + */ boolean isAnnotationResolve(); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt index e2d2bb0c0436..3b6bd281608b 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt @@ -95,7 +95,17 @@ fun GroovyFileBase.processClassesInPackage(processor: PsiScopeProcessor, state: return aPackage.processDeclarations(PackageSkippingProcessor(processor), state, null, place) } -fun PsiScopeProcessor.isAnnotationResolve(): Boolean = getHint(AnnotationHint.HINT_KEY)?.isAnnotationResolve ?: false +val PsiScopeProcessor.annotationHint: AnnotationHint? get() = getHint(AnnotationHint.HINT_KEY) + +fun PsiScopeProcessor.isAnnotationResolve(): Boolean { + val hint = annotationHint ?: return false + return hint.isAnnotationResolve +} + +fun PsiScopeProcessor.isNonAnnotationResolve(): Boolean { + val hint = annotationHint ?: return false + return !hint.isAnnotationResolve +} fun GrCodeReferenceElement.isAnnotationReference(): Boolean { val (possibleAnnotation, _) = skipSameTypeParents() diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt index 7acf91608263..e2aedc3a7dad 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt @@ -9,11 +9,8 @@ import com.intellij.psi.PsiElement import com.intellij.psi.ResolveState import com.intellij.psi.scope.PsiScopeProcessor import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase -import org.jetbrains.plugins.groovy.lang.resolve.checkName -import org.jetbrains.plugins.groovy.lang.resolve.processClassesInFile -import org.jetbrains.plugins.groovy.lang.resolve.processClassesInPackage +import org.jetbrains.plugins.groovy.lang.resolve.* import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassProcessor -import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessClasses /** * Represents regular import, possibly aliased. @@ -41,6 +38,7 @@ data class RegularImport(val classFqn: String, override val name: String) : Groo } override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFileBase): Boolean { + if (processor.isNonAnnotationResolve()) return true if (!processor.shouldProcessClasses()) return true if (!processor.checkName(name, state)) return true diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StarImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StarImport.kt index 3a5bf79605be..c03f1ebe5a53 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StarImport.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StarImport.kt @@ -7,6 +7,7 @@ import com.intellij.psi.PsiPackage import com.intellij.psi.ResolveState import com.intellij.psi.scope.PsiScopeProcessor import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase +import org.jetbrains.plugins.groovy.lang.resolve.isNonAnnotationResolve data class StarImport(val packageFqn: String) : GroovyStarImport { @@ -18,6 +19,7 @@ data class StarImport(val packageFqn: String) : GroovyStarImport { } override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFileBase): Boolean { + if (processor.isNonAnnotationResolve()) return true val pckg = resolveImport(file) ?: return true return pckg.processDeclarations(processor, state, null, place) } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt index a58ef2f5cbfe..d89ee2eb19a6 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt @@ -8,6 +8,7 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils.* import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.NonFqnImport +import org.jetbrains.plugins.groovy.lang.resolve.isAnnotationResolve import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolverProcessor import org.jetbrains.plugins.groovy.lang.resolve.processors.StaticMembersFilteringProcessor import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessMembers @@ -38,6 +39,7 @@ data class StaticImport constructor( override val isAliased: Boolean = memberName != name override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFileBase): Boolean { + if (processor.isAnnotationResolve()) return true if (!processor.shouldProcessMembers()) return true val clazz = resolveImport(file) ?: return true val namesMapping = namesMapping() diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticStarImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticStarImport.kt index 6118b3d4f290..35a1f4811590 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticStarImport.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticStarImport.kt @@ -8,6 +8,7 @@ import com.intellij.psi.ResolveState import com.intellij.psi.scope.PsiScopeProcessor import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase import org.jetbrains.plugins.groovy.lang.resolve.imports.impl.NonFqnImport +import org.jetbrains.plugins.groovy.lang.resolve.isAnnotationResolve import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolverProcessor import org.jetbrains.plugins.groovy.lang.resolve.processors.StaticMembersFilteringProcessor @@ -16,6 +17,7 @@ data class StaticStarImport(override val classFqn: String) : NonFqnImport(), Gro override val fqn: String get() = classFqn override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFileBase): Boolean { + if (processor.isAnnotationResolve()) return true val clazz = resolveImport(file) ?: return true for (each in GroovyResolverProcessor.allProcessors(processor)) { val filteringProcessor = StaticMembersFilteringProcessor(each, null) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ClassProcessor.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ClassProcessor.kt index f448e0157e80..40fd559e1a9e 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ClassProcessor.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ClassProcessor.kt @@ -35,7 +35,7 @@ class ClassProcessor( @Suppress("UNCHECKED_CAST") override fun getHint(hintKey: Key): T? { - if (hintKey == AnnotationHint.HINT_KEY) return this as T + if (hintKey == AnnotationHint.HINT_KEY && annotationResolve) return this as T return super.getHint(hintKey) }