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()) +} 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() 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; } 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/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/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(); 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/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/GroovyFileBaseImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileBaseImpl.java index a8782efe0a17..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 @@ -1,29 +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.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; @@ -45,14 +39,34 @@ 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; + +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; + private final DeclarationHolder myAllCachedDeclarations; + 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); + myAllCachedDeclarations = (processor, state, place) -> + myAnnotationsCache.getValue().processDeclarations(processor, state, place) && + myDeclarationsCache.getValue().processDeclarations(processor, state, place); } public GroovyFileBaseImpl(IFileElementType root, IFileElementType root1, FileViewProvider provider) { @@ -204,4 +218,55 @@ 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) { + return getAppropriateHolder(processor).processDeclarations(processor, state, place); + } + + @NotNull + private DeclarationHolder getAppropriateHolder(@NotNull PsiScopeProcessor processor) { + AnnotationHint hint = getAnnotationHint(processor); + if (hint == null) { + if (useCache()) { + return myAllCachedDeclarations; + } + else { + return this::processDeclarationsNoCache; + } + } + else if (hint.isAnnotationResolve()) { + return myAnnotationsCache.getValue(); + } + else { + return myDeclarationsCache.getValue(); + } + } + + 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; + 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 934be614c4df..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 @@ -5,20 +5,17 @@ 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; -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; @@ -36,18 +33,15 @@ 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.processors.ClassHint; -import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolverProcessor; +import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyFileImports; +import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImports; import java.util.concurrent.ConcurrentMap; @@ -71,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 @@ -121,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) { @@ -181,39 +121,17 @@ 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; - } - - 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; - } - } + if (!super.processDeclarations(processor, state, lastParent, place)) 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 (ResolveUtil.shouldProcessPackages(classHint)) { NameHint nameHint = processor.getHint(NameHint.KEY); @@ -247,18 +165,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 +179,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, @@ -540,6 +435,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/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/impl/psiImplUtil.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/psiImplUtil.kt index 52ed1d0f7a37..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 @@ -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.kind + else -> CodeReferenceKind.REFERENCE + } +} 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..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 @@ -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; @@ -173,15 +159,10 @@ public abstract class GrMethodBaseImpl extends GrStubElementBase i @NotNull ResolveState state, @Nullable PsiElement lastParent, @NotNull PsiElement place) { - ElementClassHint classHint = processor.getHint(ElementClassHint.KEY); + final GrTypeParameterList list = getTypeParameterList(); + if (list != null && !list.processDeclarations(processor, state, lastParent, place)) return false; - if (ResolveUtil.shouldProcessClasses(classHint)) { - 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/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/toplevel/imports/GrImportStatementImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/toplevel/imports/GrImportStatementImpl.java index 939af2b19cc6..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 @@ -1,28 +1,13 @@ -/* - * 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; 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; @@ -34,26 +19,16 @@ 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.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.imports.GroovyImport; -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; /** * @author ilyas @@ -64,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(); @@ -363,4 +179,10 @@ public class GrImportStatementImpl extends GrStubElementBase { - - @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, RESOLVER); + return TypeInferenceHelper.getCurrentContext().multiResolve(this, incompleteCode, GrCodeReferencePolyVariantResolver.INSTANCE); } @NotNull @@ -483,4 +208,10 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl 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; + } } 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 new file mode 100644 index 000000000000..91e4aee29276 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/utils/psiImportUtil.kt @@ -0,0 +1,44 @@ +// 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("PsiImportUtil") + +package org.jetbrains.plugins.groovy.lang.psi.impl.utils + +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement +import org.jetbrains.plugins.groovy.lang.resolve.imports.* +import org.jetbrains.plugins.groovy.lang.resolve.qualifiedReferenceName + +internal fun GrImportStatement.createImportFromStatement(): GroovyImport? { + val reference = importReference ?: return null + val static = isStatic + val star = isOnDemand + return if (static && star) { + StaticStarImport(classFqn = reference.qualifiedReferenceName ?: return null) + } + else if (static) { + val qualifier = reference.qualifier + val name = reference.referenceName ?: return null + val importedName = importedName ?: return null + if (qualifier == null) { + RegularImport( + classFqn = name, + name = importedName + ) + } + else { + StaticImport( + classFqn = qualifier.qualifiedReferenceName ?: return null, + memberName = name, + name = importedName + ) + } + } + else if (star) { + StarImport(packageFqn = reference.qualifiedReferenceName ?: return null) + } + else { + RegularImport( + classFqn = reference.qualifiedReferenceName ?: return null, + name = importedName ?: 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/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..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 @@ -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; @@ -27,18 +23,15 @@ 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; 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; 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; @@ -48,6 +41,9 @@ 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; + /** * @author Maxim.Medvedev */ @@ -166,10 +162,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(); @@ -197,15 +197,12 @@ 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 - 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); @@ -280,17 +277,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; } @@ -367,44 +368,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/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/psi/util/psiTreeUtil.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/psiTreeUtil.kt index b15ca1ff4d51..40f959671fa7 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/psiTreeUtil.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/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 org.jetbrains.plugins.groovy.lang.psi.util import com.intellij.openapi.progress.ProgressManager @@ -49,3 +35,13 @@ fun PsiElement.skipParentsOfType(strict: Boolean = false, vararg types: Class<*> 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/AnnotationHint.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/AnnotationHint.java new file mode 100644 index 000000000000..c989fb59d15b --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/AnnotationHint.java @@ -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.openapi.util.Key; + +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/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 +} 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/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/DefaultImportContributor.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/DefaultImportContributor.kt deleted file mode 100644 index a7ad254ebf07..000000000000 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/DefaultImportContributor.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ -package org.jetbrains.plugins.groovy.lang.resolve - -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile - -private val classes = listOf( - Import("java.math.BigInteger"), - Import("java.math.BigDecimal") -) - -private val packages = listOf( - Import("java.lang", ImportType.STAR), - Import("java.util", ImportType.STAR), - Import("java.io", ImportType.STAR), - Import("java.net", ImportType.STAR), - Import("groovy.lang", ImportType.STAR), - Import("groovy.util", ImportType.STAR) -) - -private val imports = classes + packages - -class DefaultImportContributor : GrImportContributor { - - override fun getImports(file: GroovyFile): Collection = imports -} \ No newline at end of file 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..ded23c3e2224 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrCodeReferenceResolver.kt @@ -0,0 +1,232 @@ +// 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.* +import com.intellij.psi.scope.PsiScopeProcessor +import com.intellij.psi.util.contextOfType +import com.intellij.psi.util.parentOfType +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.types.CodeReferenceKind.* +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 { + return when (ref.kind) { + PACKAGE_REFERENCE -> ref.resolveAsPackageReference() + IMPORT_REFERENCE -> ref.resolveAsImportReference() + REFERENCE -> ref.resolveReference() + } + } +} + +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.resolveImport(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.resolveImport(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, isAnnotationReference()) + 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) +} + +fun GrCodeReferenceElement.processClasses(processor: PsiScopeProcessor, state: ResolveState): Boolean { + val qualifier = qualifier + if (qualifier == null) { + return processUnqualified(processor, state) + } + else { + return processQualifier(qualifier, processor, state) + } +} + +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, + processor: PsiScopeProcessor, + state: ResolveState): Boolean { + for (result in qualifier.multiResolve(false)) { + val clazz = result.element as? PsiClass ?: continue + if (!clazz.processDeclarations(processor, state.put(PsiSubstitutor.KEY, result.substitutor), null, this)) return false + } + return true +} + +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) +} + +/** + * 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 + +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 file +} 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..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 @@ -181,7 +180,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 +191,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) } @@ -207,16 +206,3 @@ private fun GrReferenceExpression.resolveLocalVariable(): GroovyResolveResult? { treeWalkUp(processor, state) 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 - } - return parts.reversed().joinToString(separator = ".") -} 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/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 +} 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..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 @@ -1,15 +1,24 @@ // 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.GroovyFileBase +import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement 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.psi.util.skipSameTypeParents 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") @@ -22,6 +31,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 } @@ -30,10 +46,27 @@ fun PsiScopeProcessor.shouldProcessDynamicProperties(): Boolean { return getHint(DynamicMembersHint.KEY)?.shouldProcessProperties() ?: false } -fun PsiScopeProcessor.shoudProcessMethods(): Boolean { +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.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 } @@ -45,3 +78,36 @@ fun getDefaultConstructor(clazz: PsiClass): PsiMethod { Result.create(DefaultConstructor(clazz), clazz) } } + +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 + for (definition in typeDefinitions) { + if (!ResolveUtil.processElement(processor, definition, state)) return false + } + return true +} + +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) +} + +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() + return possibleAnnotation is GrAnnotation +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/DeclarationHolder.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/DeclarationHolder.kt new file mode 100644 index 000000000000..c15431990060 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/DeclarationHolder.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 DeclarationHolder { + + fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean +} 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) + } +} 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..60a8420d3349 --- /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(): DeclarationHolder { + return CachedValuesManager.getCachedValue(this) { + makeResult(buildCache(this::processInnersInHierarchyNoCache)) + } +} + +fun GrTypeDefinition.getInnersOutersCache(): DeclarationHolder { + 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): DeclarationHolder { + 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(): DeclarationHolder = ClassCache(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 ClassCache(private val classMap: Map) : DeclarationHolder { + + override fun processDeclarations(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/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/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/GroovyFileImports.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyFileImports.kt new file mode 100644 index 000000000000..9e2f54a8f5a9 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/GroovyFileImports.kt @@ -0,0 +1,34 @@ +// 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.GroovyFileBase +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement + +interface GroovyFileImports { + + val file: GroovyFileBase + + + val starImports: Collection + + val staticStarImports: Collection + + val allNamedImports: 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 new file mode 100644 index 000000000000..0fc760dc7a90 --- /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.GroovyFileBase + +interface GroovyImport { + + /** + * Resolves current import using [file] as a context + */ + fun resolveImport(file: GroovyFileBase): PsiElement? + + /** + * Feeds the processor with elements available via this import + */ + fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, file: GroovyFileBase): 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 { + + 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..e2aedc3a7dad --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/RegularImport.kt @@ -0,0 +1,77 @@ +// 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 +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.* +import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassProcessor + +/** + * 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` + */ +data class RegularImport(val classFqn: String, override val name: String) : GroovyNamedImport { + + constructor(classFqn: String) : this(classFqn, StringUtil.getShortName(classFqn)) + + override val isAliased: Boolean = getShortName(classFqn) != name + + 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: GroovyFileBase): Boolean { + if (processor.isNonAnnotationResolve()) return true + if (!processor.shouldProcessClasses()) return true + if (!processor.checkName(name, state)) return true + + val clazz = resolveImport(file) ?: return true + 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 new file mode 100644 index 000000000000..c03f1ebe5a53 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StarImport.kt @@ -0,0 +1,30 @@ +// 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.GroovyFileBase +import org.jetbrains.plugins.groovy.lang.resolve.isNonAnnotationResolve + +data class StarImport(val packageFqn: String) : GroovyStarImport { + + override val fqn: String get() = packageFqn + + 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: GroovyFileBase): Boolean { + if (processor.isNonAnnotationResolve()) return true + val pckg = resolveImport(file) ?: return true + 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 new file mode 100644 index 000000000000..d89ee2eb19a6 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticImport.kt @@ -0,0 +1,83 @@ +// 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.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 + +/** + * 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` + */ +data class StaticImport constructor( + override val classFqn: String, + val memberName: String, + override val name: String +) : NonFqnImport(), GroovyNamedImport { + + 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: GroovyFileBase): Boolean { + if (processor.isAnnotationResolve()) return true + if (!processor.shouldProcessMembers()) return true + val clazz = resolveImport(file) ?: return true + 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, 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) + + 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..35a1f4811590 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/StaticStarImport.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. +@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.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 + +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: GroovyFileBase): Boolean { + if (processor.isAnnotationResolve()) return true + 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 + } + 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 new file mode 100644 index 000000000000..8f7447c3ec36 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyFileImportsImpl.kt @@ -0,0 +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 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.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 file: GroovyFileBase, + private val imports: Map, Collection>, + private val statementToImport: Map, + private val importToStatement: Map +) : GroovyFileImports { + + @Suppress("UNCHECKED_CAST") + private fun getImports(kind: ImportKind): Collection { + val collection = imports[kind] ?: return emptyList() + return collection as Collection + } + + 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)) + + private fun addStatement(state: ResolveState, import: GroovyImport): ResolveState { + val statement = importToStatement[import] ?: return state + return state.put(ClassHint.RESOLVE_CONTEXT, statement) + } + + @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.resolveImport(file) == null) { + result += statement + } + } + + for (import in allNamedImports) { + if (import.name !in names) continue + val statement = importToStatement[import] ?: continue + if (import.resolveImport(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..35c99d0fcb89 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/GroovyImportCollector.kt @@ -0,0 +1,93 @@ +// 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.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: GroovyFileBase) { + + 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 addRegularImport(import: RegularImport) { + getMap(ImportKind.Regular)[import.name] = import + } + + private fun addStaticImport(import: StaticImport) { + getMap(ImportKind.Static)[import.name] = import + } + + private fun addStarImport(import: StarImport) { + getMap(ImportKind.Star)[import.packageFqn] = import + } + + private fun addStaticStarImport(import: StaticStarImport) { + getMap(ImportKind.StaticStar)[import.classFqn] = import + } + + private fun addImport(import: GroovyImport) = when (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 + addImport(import) + } + + internal fun addImportFromContributor(contributedImport: Import) { + val name = contributedImport.name + when (contributedImport.type) { + ImportType.REGULAR -> addRegularImport(name, getShortName(name)) + ImportType.STATIC -> addStaticImport(getPackageName(name), getShortName(name)) + ImportType.STAR -> addStarImport(name) + ImportType.STATIC_STAR -> addStaticStarImport(name) + } + } + + 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/NonFqnImport.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/NonFqnImport.kt new file mode 100644 index 000000000000..d6baf5a17a53 --- /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.GroovyFileBase +import org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyImport + +abstract class NonFqnImport : GroovyImport { + + abstract val classFqn: String + + override fun resolveImport(file: GroovyFileBase): 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/strategies.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/strategies.kt new file mode 100644 index 000000000000..79a0bd7d69f1 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/impl/strategies.kt @@ -0,0 +1,28 @@ +// 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.packageFqn == o2.packageFqn + } + + override fun computeHashCode(o: StarImport?): Int = o?.packageFqn?.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..45fb313ba002 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/imports.kt @@ -0,0 +1,47 @@ +// 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.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.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) + +val importedNameKey = Key.create("groovy.imported.via.name") + +fun GroovyFile.getImports(): GroovyFileImports { + return CachedValuesManager.getCachedValue(this) { + Result.create(doGetImports(), this) + } +} + +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 new file mode 100644 index 000000000000..09018265afd1 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/imports/unusedImports.kt @@ -0,0 +1,67 @@ +// 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") + +package org.jetbrains.plugins.groovy.lang.resolve.imports + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiRecursiveElementWalkingVisitor +import com.intellij.util.containers.HashSet +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 + +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 + } + + val usedStatements = HashSet(referencedStatements) + usedStatements -= imports.findUnneecessaryStatements() + usedStatements += imports.findUnresolvedStatements(unresolvedReferenceNames) + 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 { + results.mapNotNullTo(referencedStatements) { + it.currentFileResolveContext as? GrImportStatement + } + } + } +} 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..59f46bb1ac96 --- /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().processDeclarations(processor, state, place) + } + else { + return processInnersInHierarchyNoCache(processor, state, place) + } +} + +fun GrTypeDefinition.processInnersInOuters(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { + if (useCaches(place)) { + return getInnersOutersCache().processDeclarations(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 +} 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/ClassProcessor.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ClassProcessor.kt new file mode 100644 index 000000000000..40fd559e1a9e --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/ClassProcessor.kt @@ -0,0 +1,43 @@ +// 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.* +import com.intellij.util.SmartList +import org.jetbrains.plugins.groovy.lang.resolve.AnnotationHint +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, + private val annotationResolve: Boolean = false +) : GrScopeProcessorWithHints(name, RESOLVE_KINDS_CLASS), AnnotationHint, 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 + } + + @Suppress("UNCHECKED_CAST") + override fun getHint(hintKey: Key): T? { + if (hintKey == AnnotationHint.HINT_KEY && annotationResolve) return this as T + return super.getHint(hintKey) + } + + override fun isAnnotationResolve(): Boolean = annotationResolve +} 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/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 + } +} 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/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; } 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"); } 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); } 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 +} 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) +} 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() + } +} 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/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 4f17314f0587..f120ba6a6fa2 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -284,7 +284,6 @@ - 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; - } -} 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 5142e1af4d29..022deb1f0aea 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 @@ -329,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); @@ -602,7 +602,7 @@ 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); + 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 new file mode 100644 index 000000000000..d2b0050cf4a2 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/completeReferenceElement.kt @@ -0,0 +1,153 @@ +// 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 +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 +} 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); } } } 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; } } } 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/ResolveClassInNewTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassInNewTest.groovy new file mode 100644 index 000000000000..3ec35bcda4c2 --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassInNewTest.groovy @@ -0,0 +1,179 @@ +// 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 + +import static com.intellij.openapi.util.RecursionManager.assertOnRecursionPrevention + +@CompileStatic +class ResolveClassInNewTest extends LightGroovyTestCase { + + final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + + 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", '/' + 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 6b03da2ee665..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 @@ -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() { @@ -604,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 {} @@ -618,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/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 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 {}