Merge branch 'daniil/groovy-imports'

This commit is contained in:
Daniil Ovchinnikov
2017-11-26 14:32:29 +03:00
173 changed files with 5413 additions and 1742 deletions
@@ -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 <reified T : PsiElement> PsiElement.parentsOfType(): Sequence<T> = pa
fun <T : PsiElement> PsiElement.parentsOfType(clazz: Class<out T>): Sequence<T> = parents().filterIsInstance(clazz)
fun PsiElement.parents(): Sequence<PsiElement> = generateSequence(this) { it.parent }
inline fun <reified T : PsiElement> PsiElement.contextOfType(): T? = contextOfType(T::class)
fun <T : PsiElement> PsiElement.contextOfType(vararg classes: KClass<out T>): T? {
return PsiTreeUtil.getContextOfType(this, *classes.map { it.java }.toTypedArray())
}
@@ -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<T> = Pair<T, T?>
@@ -41,3 +27,5 @@ private class LookbackIterator<T>(private val iterator: Iterator<T>) : Iterator<
return result
}
}
fun <K, V : Any> Map<K, V>.reverse(): Map<V, K> = map { (k, v) -> v to k }.toMap()
@@ -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> T get(@NotNull Key<T> key) {
if (key instanceof KeyWithDefaultValue) {
return ((KeyWithDefaultValue<T>)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> T get(@NotNull Key<T> 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> T get(@NotNull Key<T> key) {
Object value;
@@ -126,15 +148,30 @@ public class ResolveState {
private static class ManyElementResolveState extends ResolveState {
private final Map<Object, Object> 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> T get(@NotNull Key<T> key) {
final T value = (T)myValues.get(key);
if (value == null && key instanceof KeyWithDefaultValue) {
return ((KeyWithDefaultValue<T>) key).getDefaultValue();
return ((KeyWithDefaultValue<T>)key).getDefaultValue();
}
return value;
}
@@ -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<GrImportStatement> myUnusedImports;
private volatile List<HighlightInfo> 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<GrImportStatement> unusedImports = new HashSet<>(PsiUtil.getValidImportStatements(myFile));
unusedImports.removeAll(GroovyImportUtil.findUsedImports(myFile));
myUnusedImports = unusedImports;
myUnusedImports = unusedImports(myFile);
if (deadCodeEnabled) {
for (GrParameter parameter : usedParams.keySet()) {
@@ -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<String, GrImportStatement> myPseudoImports = ContainerUtil.newLinkedHashMap();
private final ArrayList<GrImportStatement> myOnDemandImports = ContainerUtil.newArrayList();
private final GroovyImportCollector myImportCollector = new GroovyImportCollector(this);
private final ClearableLazyValue<GroovyFileImports> 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<String, GrImportStatement> 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();
}
}
@@ -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();
@@ -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();
@@ -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();
}
@@ -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
}
@@ -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> {
GrCodeReferenceElement[] EMPTY_ARRAY = new GrCodeReferenceElement[0];
@NotNull
CodeReferenceKind getKind();
}
@@ -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<DeclarationHolder> myAnnotationsCache;
private final CachedValue<DeclarationHolder> 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();
}
@@ -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<MostlySingularMultiMap<String, ResultWithContext>> 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<String, ResultWithContext> cache) {
for (PsiScopeProcessor each : GroovyResolverProcessor.allProcessors(processor)) {
String name = ResolveUtil.getNameHint(each);
Processor<ResultWithContext> 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<String, ResultWithContext> buildDeclarationCache() {
MostlySingularMultiMap<String, ResultWithContext> 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()) {
@@ -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;
}
}
@@ -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<out GrVariableDeclaration> {
val tree = stubTree ?: return collectScriptDeclarations(topLevelOnly)
@@ -66,4 +56,14 @@ private fun GroovyFileImpl.doCollectScriptDeclarations(topLevelOnly: Boolean): A
}
})
return result.toTypedArray()
}
}
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
}
}
@@ -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<GrMethodStub> 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;
}
@@ -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;
}
}
@@ -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<GrImportStatementSt
super(node);
}
public GrImportStatementImpl(GrImportStatementStub stub, IStubElementType nodeType) {
public GrImportStatementImpl(@NotNull GrImportStatementStub stub, @NotNull IStubElementType nodeType) {
super(stub, nodeType);
}
@@ -82,53 +57,7 @@ public class GrImportStatementImpl extends GrStubElementBase<GrImportStatementSt
@NotNull ResolveState state,
@Nullable PsiElement lastParent,
@NotNull PsiElement place) {
if (!shouldProcess(processor)) return true;
if (isAncestor(place)) return true;
if (isStatic() && lastParent instanceof GrImportStatement) return true;
if (isOnDemand()) {
if (!processDeclarationsForMultipleElements(processor, lastParent, place, state)) return false;
}
else {
if (!processDeclarationsForSingleElement(processor, lastParent, place, state)) return false;
}
return true;
}
private static boolean shouldProcess(PsiScopeProcessor processor) {
ElementClassHint classHint = processor.getHint(ElementClassHint.KEY);
return classHint == null ||
classHint.shouldProcess(CLASS) ||
classHint.shouldProcess(METHOD) ||
classHint.shouldProcess(ElementClassHint.DeclarationKind.FIELD) ||
classHint.shouldProcess(ElementClassHint.DeclarationKind.ENUM_CONST);
}
private boolean isAncestor(@Nullable PsiElement place) {
while (place instanceof GrCodeReferenceElement) {
PsiElement parent = place.getParent();
if (parent == this) return true;
place = parent;
}
return false;
}
private boolean processDeclarationsForSingleElement(@NotNull PsiScopeProcessor processor,
@Nullable PsiElement lastParent,
@NotNull PsiElement place,
@NotNull ResolveState state) {
String name = getImportedName();
if (name == null) return true;
if (isStatic()) {
return processSingleStaticImport(processor, state, name, lastParent, place);
}
NameHint nameHint = processor.getHint(NameHint.KEY);
if (nameHint == null || name.equals(nameHint.getName(state))) {
return processSingleClassImport(processor, state);
}
PsiUtil.LOG.warn("Use org.jetbrains.plugins.groovy.lang.resolve.imports.GroovyFileImports");
return true;
}
@@ -143,119 +72,6 @@ public class GrImportStatementImpl extends GrStubElementBase<GrImportStatementSt
});
}
private boolean processSingleStaticImport(@NotNull final PsiScopeProcessor processor,
@NotNull ResolveState state,
@NotNull String importedName,
@Nullable PsiElement lastParent,
@NotNull PsiElement place) {
final GrCodeReferenceElement ref = getImportReference();
if (ref == null) return true;
final PsiClass clazz = resolveQualifier();
if (clazz == null) return true;
state = state.put(ClassHint.RESOLVE_CONTEXT, this);
final String refName = ref.getReferenceName();
if (refName == null) return true;
final Iterable<Pair<String, String>> namesMapping = namesMapping(importedName, refName);
for (PsiScopeProcessor each : GroovyResolverProcessor.allProcessors(processor)) {
final String hintName = ResolveUtil.getNameHint(each);
for (Pair<String, String> 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<Pair<String, String>> namesMapping(@NotNull String importedName, @NotNull String refName) {
if (importedName.equals(refName)) {
Iterable<String> importedNames = names(importedName);
return zip(importedNames, importedNames);
}
else {
return zip(names(importedName), names(refName));
}
}
private static Iterable<String> names(@NotNull String importedName) {
List<String> 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<GrImportStatementSt
return findChildByType(GroovyTokenTypes.mIDENT);
}
@Nullable
@Override
public GroovyImport getImport() {
return createImportFromStatement(this);
}
}
@@ -6,41 +6,26 @@ import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.ResolveCache;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocReferenceElement;
import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.types.CodeReferenceKind;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrReferenceElementImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ElementGroovyResult;
import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassResolverProcessor;
import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor;
import org.jetbrains.plugins.groovy.lang.resolve.GrCodeReferencePolyVariantResolver;
import java.util.ArrayList;
import java.util.List;
import static org.jetbrains.plugins.groovy.lang.psi.util.PsiTreeUtilKt.treeWalkUp;
import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil.collapseReflectedMethodsSimple;
import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil.filterAccessorMethods;
import static org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtilKt.doGetKind;
import static org.jetbrains.plugins.groovy.lang.resolve.ReferencesKt.getQualifiedReferenceName;
/**
* @author: Dmitry.Krasilschikov
@@ -93,69 +78,23 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl<GrCodeRef
return findChildByType(TokenSets.CODE_REFERENCE_ELEMENT_NAME_TOKENS);
}
public enum ReferenceKind {
CLASS,
CLASS_OR_PACKAGE,
PACKAGE_FQ,
CLASS_FQ,
CLASS_OR_PACKAGE_FQ,
STATIC_MEMBER_FQ,
}
public ReferenceKind getKind(boolean forCompletion) {
if (isClassReferenceForNew()) {
return ReferenceKind.CLASS_OR_PACKAGE;
}
PsiElement parent = getParent();
if (parent instanceof GrCodeReferenceElementImpl) {
ReferenceKind parentKind = ((GrCodeReferenceElementImpl)parent).getKind(forCompletion);
if (parentKind == ReferenceKind.CLASS) {
return ReferenceKind.CLASS_OR_PACKAGE;
}
else if (parentKind == ReferenceKind.STATIC_MEMBER_FQ) {
return isQualified() ? ReferenceKind.CLASS_FQ : ReferenceKind.CLASS;
}
else if (parentKind == ReferenceKind.CLASS_FQ) return ReferenceKind.CLASS_OR_PACKAGE_FQ;
return parentKind;
}
else if (parent instanceof GrPackageDefinition) {
return ReferenceKind.PACKAGE_FQ;
}
else if (parent instanceof GrDocReferenceElement) {
return ReferenceKind.CLASS_OR_PACKAGE;
}
else if (parent instanceof GrImportStatement) {
final GrImportStatement importStatement = (GrImportStatement)parent;
if (importStatement.isStatic()) {
return importStatement.isOnDemand() ? ReferenceKind.CLASS : ReferenceKind.STATIC_MEMBER_FQ;
}
else {
return forCompletion || importStatement.isOnDemand() ? ReferenceKind.CLASS_OR_PACKAGE_FQ : ReferenceKind.CLASS_FQ;
}
}
else if (parent instanceof GrNewExpression || parent instanceof GrAnonymousClassDefinition) {
PsiElement newExpr = parent instanceof GrAnonymousClassDefinition ? parent.getParent() : parent;
assert newExpr instanceof GrNewExpression;
}
return ReferenceKind.CLASS;
}
@Override
@NotNull
public String getCanonicalText() {
final ReferenceKind kind = getKind(false);
switch (kind) {
case CLASS:
case CLASS_OR_PACKAGE:
switch (getKind()) {
case PACKAGE_REFERENCE:
case IMPORT_REFERENCE:
return getTextSkipWhiteSpaceAndComments();
case REFERENCE:
final PsiElement target = resolve();
if (target instanceof PsiClass) {
if (target instanceof PsiTypeParameter) {
return StringUtil.notNullize(((PsiTypeParameter)target).getName());
}
else if (target instanceof PsiClass) {
final PsiClass aClass = (PsiClass)target;
String name = aClass.getQualifiedName();
if (name == null) { //parameter types don't have qualified name
name = aClass.getName();
}
if (name == null) return "";
final PsiType[] types = getTypeArguments();
if (types.length == 0) return name;
@@ -177,15 +116,8 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl<GrCodeRef
LOG.assertTrue(target == null);
return getTextSkipWhiteSpaceAndComments();
}
case CLASS_FQ:
case CLASS_OR_PACKAGE_FQ:
case PACKAGE_FQ:
case STATIC_MEMBER_FQ:
return getTextSkipWhiteSpaceAndComments();
default:
LOG.assertTrue(false);
return null;
throw new IllegalStateException();
}
}
@@ -207,17 +139,20 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl<GrCodeRef
@Override
public boolean isFullyQualified() {
switch (getKind(false)) {
case PACKAGE_FQ:
case CLASS_FQ:
case CLASS_OR_PACKAGE_FQ:
case STATIC_MEMBER_FQ:
case CLASS_OR_PACKAGE:
if (resolve() instanceof PsiPackage) return true;
case CLASS:
PsiElement resolved = resolve();
if (resolved instanceof PsiPackage) {
return true;
}
else if (resolved instanceof PsiClass) {
final String qualifiedReferenceName = getQualifiedReferenceName(this);
if (qualifiedReferenceName == null) return false;
final String classFqn = ((PsiClass)resolved).getQualifiedName();
if (classFqn == null) return false;
return qualifiedReferenceName.equals(classFqn);
}
else {
return false;
}
final GrCodeReferenceElement qualifier = getQualifier();
return qualifier != null && ((GrCodeReferenceElementImpl)qualifier).isFullyQualified();
}
@Override
@@ -238,225 +173,15 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl<GrCodeRef
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
private boolean isClassReferenceForNew() {
PsiElement parent = getParent();
while (parent instanceof GrCodeReferenceElement) parent = parent.getParent();
return parent instanceof GrNewExpression;
}
@Override
public boolean isSoft() {
return false;
}
private static class OurResolver implements ResolveCache.PolyVariantResolver<GrCodeReferenceElementImpl> {
@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<GroovyResolveResult> 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<GroovyResolveResult> 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<GroovyResolveResult> result) {
final List<GroovyResolveResult> 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<GroovyResolveResult> 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<GroovyResolveResult> 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<GroovyResolveResult> 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<GrCodeRef
return PsiType.EMPTY_ARRAY;
}
@NotNull
@Override
public CodeReferenceKind getKind() {
return doGetKind(this);
}
}
@@ -1,25 +1,13 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.groovy.lang.psi.impl.types;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiTypeParameter;
import com.intellij.psi.ResolveState;
import com.intellij.psi.StubBasedPsiElement;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.stubs.EmptyStub;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
@@ -32,6 +20,9 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameterList;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrStubElementBase;
import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil.processElement;
import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.shouldProcessTypeParameters;
/**
* @author ilyas
*/
@@ -123,4 +114,16 @@ public class GrTypeParameterListImpl extends GrStubElementBase<EmptyStub> 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;
}
}
@@ -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
)
}
}
@@ -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<T>' 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
@@ -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<PsiClass> 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<String, CandidateInfo> 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<PsiClass> 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<PsiClass> classes = RecursionManager.doPreventingRecursion(key, false, () -> {
List<PsiClass> 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();
@@ -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<GrImportStatement> 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<GrImportStatement> findUsedImports(GroovyFile file) {
Set<GrImportStatement> usedImports = new HashSet<>();
processFile(file, null, null, usedImports, null, null, null, null, null);
return usedImports;
}
}
@@ -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 <reified T : PsiElement> T.skipSameTypeParents(): Pair<PsiElement?, T> {
var lastParent: T = this
var parent: PsiElement? = parent
while (parent is T) {
lastParent = parent
parent = parent.parent
}
return Pair(parent, lastParent)
}
@@ -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<AnnotationHint> 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();
}
@@ -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<out T : PsiElement>(
element: T,
protected val myPlace: PsiElement?,
private val myResolveContext: PsiElement? = null,
protected val mySubstitutor: PsiSubstitutor = PsiSubstitutor.EMPTY
) : ElementGroovyResult<T>(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
}
@@ -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
@@ -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<PsiClass>(element, place, resolveContext, substitutor)
@@ -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<Import> = imports
}
@@ -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<GrCodeReferenceElement> {
override fun resolve(t: GrCodeReferenceElement, incompleteCode: Boolean): Array<GroovyResolveResult> {
return ContainerUtil.toArray(GrCodeReferenceResolver.resolve(t, incompleteCode), GroovyResolveResult.EMPTY_ARRAY)
}
}
@@ -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<GrCodeReferenceElement> {
override fun resolve(ref: GrCodeReferenceElement, incomplete: Boolean): Collection<GroovyResolveResult> {
return when (ref.kind) {
PACKAGE_REFERENCE -> ref.resolveAsPackageReference()
IMPORT_REFERENCE -> ref.resolveAsImportReference()
REFERENCE -> ref.resolveReference()
}
}
}
private fun GrCodeReferenceElement.resolveAsPackageReference(): Collection<GroovyResolveResult> {
val fqn = qualifiedReferenceName ?: return emptyList()
val pckg = JavaPsiFacade.getInstance(project).findPackage(fqn) ?: return emptyList()
return listOf(ElementGroovyResult(pckg))
}
private fun GrCodeReferenceElement.resolveAsImportReference(): Collection<GroovyResolveResult> {
val file = containingFile as? GroovyFile ?: return emptyList()
val statement = parentOfType<GrImportStatement>() ?: 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<GroovyResolveResult> {
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<GroovyResolveResult> {
val resolved = import.resolveImport(file) ?: return emptyList()
return listOf(ElementGroovyResult(resolved))
}
private fun GrCodeReferenceElement.resolveReference(): Collection<GroovyResolveResult> {
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<GroovyResolveResult> {
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<GroovyResolveResult> {
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<GrTypeDefinition>() ?: 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
}
@@ -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<String>()
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 = ".")
}
@@ -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<out T : GroovyResolveResult> : PsiScopeProcessor {
val results: List<T>
val resultsArray: Array<GroovyResolveResult> get() = toArray(results, GroovyResolveResult.EMPTY_ARRAY)
}
@@ -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<T : GroovyPolyVariantReference> : AbstractResolver<T, Collection<GroovyResolveResult>> {
override fun resolve(ref: T, incomplete: Boolean): Collection<GroovyResolveResult>
}
@@ -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<Boolean?>("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
}
@@ -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
}
@@ -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<String, ElementWithState>()
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 <T : Any?> getHint(hintKey: Key<T>): 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<String, ElementWithState>) : 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)
}
}
@@ -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 <T> GrTypeDefinition.makeResult(value: T): Result<T> {
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<String, PsiClass>()
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<String, PsiClass>) : 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
}
}
@@ -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<PsiElement>.collapseReflectedMethods(): Collection<PsiElement> {
return mapTo(mutableSetOf<PsiElement>()) {
(it as? GrReflectedMethod)?.baseMethod ?: it
}
}
fun Collection<PsiElement>.collapseAccessors(): Collection<PsiElement> {
val fields = filterIsInstance<GrField>()
return filter { it !is GrAccessorMethod || it.property !in fields }
}
@@ -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<Import> = 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
}
@@ -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<StarImport>
val staticStarImports: Collection<StaticStarImport>
val allNamedImports: Collection<GroovyNamedImport>
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<GrImportStatement>
fun findUnresolvedStatements(names: Collection<String>): Collection<GrImportStatement>
}
@@ -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
}
@@ -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"
}
@@ -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.*"
}
@@ -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<String> = listOf(
name,
getGetterNameNonBoolean(name),
getGetterNameBoolean(name),
getSetterName(name)
)
private fun namesMapping(left: String, right: String): List<Pair<String, String>> {
val leftNames = names(left)
val rightNames = if (left == right) leftNames
else names(
right)
return leftNames.zip(rightNames)
}
}
}
@@ -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.*"
}
@@ -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<ImportKind<*>, Collection<GroovyImport>>,
private val statementToImport: Map<GrImportStatement, GroovyImport>,
private val importToStatement: Map<GroovyImport, GrImportStatement>
) : GroovyFileImports {
@Suppress("UNCHECKED_CAST")
private fun <T : GroovyImport> getImports(kind: ImportKind<T>): Collection<T> {
val collection = imports[kind] ?: return emptyList()
return collection as Collection<T>
}
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<GroovyImport>.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<GrImportStatement> {
return statementToImport.filterValues { it.isUnnecessary(this) }.keys
}
override fun findUnresolvedStatements(names: Collection<String>): Collection<GrImportStatement> {
if (names.isEmpty()) return emptyList()
val result = HashSet<GrImportStatement>()
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}"
}
@@ -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<GrImportStatement, GroovyImport>()
private val imports = HashMap<ImportKind<*>, LinkedHashMap<String, GroovyImport>>()
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<GroovyImport> get() = imports.values.flatMap { it.values }
@Suppress("UNCHECKED_CAST")
private fun <T : GroovyImport> getMap(kind: ImportKind<T>): LinkedHashMap<String, T> {
val map = imports.getOrPut(kind) { LinkedHashMap() }
return map as LinkedHashMap<String, T>
}
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()
)
}
@@ -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<T : GroovyImport> {
internal object Regular : ImportKind<RegularImport>()
internal object Static : ImportKind<StaticImport>()
internal object Star : ImportKind<StarImport>()
internal object StaticStar : ImportKind<StaticStarImport>()
}
@@ -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)
}
}
@@ -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<RegularImport> {
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<StarImport> {
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
}
@@ -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<String>("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<GrImportStatement> get() = importStatements.filterNot(ErrorUtil::containsError)
@@ -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<GrImportStatement> {
val result = file.validImportStatements.toMutableSet()
result -= usedImports(file)
return result
}
fun usedImports(file: GroovyFile): Set<GrImportStatement> {
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<GrImportStatement>()
private val unresolvedReferenceNames = LinkedHashSet<String>()
val results: Pair<Set<GrImportStatement>, Set<String>> 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
}
}
}
}
@@ -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<GrTypeDefinition> {
val result = SmartList<GrTypeDefinition>()
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
}
@@ -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<PsiElement> RESOLVE_CONTEXT = Key.create("RESOLVE_CONTEXT");
EnumSet<DeclarationKind> RESOLVE_KINDS_CLASS_PACKAGE = EnumSet.of(CLASS, PACKAGE);
EnumSet<DeclarationKind> RESOLVE_KINDS_CLASS = EnumSet.of(CLASS);
EnumSet<DeclarationKind> RESOLVE_KINDS_METHOD = EnumSet.of(METHOD);
EnumSet<DeclarationKind> RESOLVE_KINDS_PROPERTY = EnumSet.of(VARIABLE, FIELD, ENUM_CONST);
@@ -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<out PsiType> = PsiType.EMPTY_ARRAY,
private val annotationResolve: Boolean = false
) : GrScopeProcessorWithHints(name, RESOLVE_KINDS_CLASS), AnnotationHint, GrResolverProcessor<ClassResolveResult> {
private val myResults = SmartList<ClassResolveResult>()
override val results: List<ClassResolveResult> 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 <T : Any?> getHint(hintKey: Key<T>): T? {
if (hintKey == AnnotationHint.HINT_KEY && annotationResolve) return this as T
return super.getHint(hintKey)
}
override fun isAnnotationResolve(): Boolean = annotationResolve
}
@@ -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);
}
@@ -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<PsiElement>()
val results: List<PsiElement> get() = myResults
override fun execute(element: PsiElement, state: ResolveState): Boolean {
myResults += element
return true
}
}
@@ -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() {
@@ -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<DeclarationKind> resolveTargets) {
this(delegate, null, resolveTargets);
}
public GrDelegatingScopeProcessorWithHints(@NotNull PsiScopeProcessor delegate,
@Nullable String name,
@Nullable EnumSet<DeclarationKind> resolveTargets) {
@Nullable Set<DeclarationKind> resolveTargets) {
super(name, resolveTargets);
myDelegate = delegate;
}
@@ -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> HINT_KEY = Key.create("groovy.resolve.kind.hint");
}
@@ -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);
}
@@ -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<ElementGroovyResult<PsiTypeParameter>>,
GroovyResolveKind.Hint {
private var myResult: ElementGroovyResult<PsiTypeParameter>? = null
override val results: List<ElementGroovyResult<PsiTypeParameter>>
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 <T : Any?> getHint(hintKey: Key<T>): T? {
return when (hintKey) {
GroovyResolveKind.HINT_KEY -> this as T
else -> super.getHint(hintKey)
}
}
override fun shouldProcess(kind: GroovyResolveKind): Boolean = kind == GroovyResolveKind.TYPE_PARAMETER
}
@@ -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<String>()
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)
}
@@ -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 <T> flatten(vararg collections: Collection<T>): Collection<T> = FlatCollection(collections)
private class FlatCollection<T>(private val collections: Array<out Collection<T>>) : AbstractCollection<T>() {
override val size: Int get() = collections.sumBy { it.size }
override fun iterator(): Iterator<T> = object : FlatteningIterator<Collection<T>, T>(collections.iterator()) {
override fun createValueIterator(group: Collection<T>): Iterator<T> = group.iterator()
}
}
@@ -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 <T> Consumer<T>.consumeAll(items: Iterable<T>) {
items.forEach(this::consume)
}
-1
View File
@@ -284,7 +284,6 @@
<methodComparator implementation="org.jetbrains.plugins.groovy.lang.resolve.GrDefaultMethodComparator" order="last"/>
<expectedPackageNameProvider implementation="org.jetbrains.plugins.groovy.lang.resolve.DefaultExpectedPackageNameProvider"
order="last"/>
<importContributor implementation="org.jetbrains.plugins.groovy.lang.resolve.DefaultImportContributor"/>
<delegatesToProvider implementation="org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DefaultDelegatesToProvider" id="default"/>
</extensions>
@@ -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<LookupElement> myConsumer;
private final PrefixMatcher myMatcher;
private CompleteCodeReferenceElement(@NotNull GrCodeReferenceElementImpl ref,
@NotNull Consumer<LookupElement> consumer,
@NotNull PrefixMatcher matcher) {
myRef = ref;
myConsumer = consumer;
myMatcher = matcher;
}
public static void processVariants(@NotNull GrCodeReferenceElementImpl ref,
@NotNull Consumer<LookupElement> 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<? extends LookupElement> 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;
}
}
@@ -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<LookupElement> 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);
@@ -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<LookupElement>
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 <T : Any?> getHint(hintKey: Key<T>): 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
}
@@ -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<GrImportStatement> usedImports = GroovyImportUtil.findUsedImports(file);
final Set<GrImportStatement> usedImports = usedImports(file);
final List<GrImportStatement> validImports = PsiUtil.getValidImportStatements(file);
redundants.put(file, Pair.create(validImports, usedImports));
});
@@ -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<GrImportStatement> usedImports = GroovyImportUtil.findUsedImports(file);
final List<GrImportStatement> 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);
}
}
}
@@ -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<GroovyFile, String> 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<GroovyFile, String> 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;
}
}
}
@@ -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", "FB<caret>a")
complete()
myFixture.type '.'.charAt(0)
myFixture.checkResult "a.FooBar.<caret>a"
myFixture.checkResult '''\
import a.FooBar
FooBar.<caret>a'''
}
private LookupElement[] complete() {
@@ -93,7 +82,10 @@ class GroovyClassNameCompletionTest extends LightCodeInsightFixtureTestCase {
myFixture.configureByText("a.groovy", "FBGD<caret>a")
myFixture.complete(CompletionType.BASIC, 2)
myFixture.type '.'
myFixture.checkResult "a.FooBarGooDoo.<caret>a"
myFixture.checkResult '''\
import a.FooBarGooDoo
FooBarGooDoo.<caret>a'''
}
void testDelegateBasicToClassNameAutoinsert() throws Exception {
@@ -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
}
}
@@ -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<K,V> {} } ")
myFixture.addClass("package java.util; public class MainMap { static interface Entry<K,V> {} } ")
@@ -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 Ba<caret>r() {}
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 B<caret>ar() {}
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) }
@@ -1,3 +1,3 @@
class Foo extends Inner implements <error descr="Cannot resolve symbol 'Unknown'">Unknown</error> {
class Foo extends <error descr="Cannot resolve symbol 'Inner'">Inner</error> implements <error descr="Cannot resolve symbol 'Unknown'">Unknown</error> {
static class Inner {}
}
@@ -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 {}
@@ -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 {}
@@ -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 <caret>Target()
}
}
}
}
class Main {
static void main(String[] args) {
println OuterOuter.Outer.Current.usage()
}
}
@@ -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 {}
@@ -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 {}
@@ -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 {}
@@ -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 <caret>Target()
}
}
}
}
class Main {
static void main(String[] args) {
println OuterOuter.Outer.Current.usage()
}
}
@@ -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 {}
@@ -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 {}
@@ -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 {}
@@ -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 <caret>Target()
}
}
}
}
class Main {
static void main(String[] args) {
println OuterOuter.Outer.Current.usage()
}
}
@@ -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 {}
@@ -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 {}
@@ -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 {}
@@ -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 <caret>Target()
}
}
}
}
class Main {
static void main(String[] args) {
println OuterOuter.Outer.Current.usage()
}
}
@@ -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 {}
@@ -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 {}
@@ -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 {}
@@ -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 <caret>Target()
}
}
}
}
class Main {
static void main(String[] args) {
println OuterOuter.Outer.Current.usage()
}
}
@@ -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 {}
@@ -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 {}
@@ -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 {}
@@ -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 <caret>Target()
}
}
}
}
class Main {
static void main(String[] args) {
println OuterOuter.Outer.Current.usage()
}
}

Some files were not shown because too many files have changed in this diff Show More