mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'daniil/groovy-imports'
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
+7
-23
@@ -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()) {
|
||||
|
||||
+63
-143
@@ -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
-19
@@ -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();
|
||||
|
||||
|
||||
+5
-15
@@ -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();
|
||||
|
||||
|
||||
+5
-15
@@ -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();
|
||||
}
|
||||
|
||||
+8
@@ -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
|
||||
}
|
||||
+5
-15
@@ -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();
|
||||
}
|
||||
|
||||
+80
-15
@@ -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();
|
||||
}
|
||||
|
||||
+16
-117
@@ -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
-49
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+16
-16
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+4
-23
@@ -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;
|
||||
}
|
||||
|
||||
+7
-16
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+15
-193
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+36
-305
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+18
-15
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+44
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
+4
-35
@@ -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
|
||||
|
||||
+25
-62
@@ -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
-25
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+11
-15
@@ -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)
|
||||
}
|
||||
|
||||
+17
@@ -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();
|
||||
}
|
||||
+37
@@ -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
|
||||
}
|
||||
+2
-16
@@ -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
|
||||
|
||||
+13
@@ -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)
|
||||
-39
@@ -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
|
||||
}
|
||||
+17
@@ -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)
|
||||
}
|
||||
}
|
||||
+232
@@ -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
|
||||
}
|
||||
+2
-16
@@ -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 = ".")
|
||||
}
|
||||
|
||||
+13
@@ -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)
|
||||
}
|
||||
+13
@@ -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>
|
||||
}
|
||||
+67
-1
@@ -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
|
||||
}
|
||||
|
||||
+11
@@ -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
|
||||
}
|
||||
+56
@@ -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)
|
||||
}
|
||||
}
|
||||
+80
@@ -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
-74
@@ -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
|
||||
}
|
||||
|
||||
+34
@@ -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>
|
||||
}
|
||||
+38
@@ -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
|
||||
}
|
||||
+77
@@ -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"
|
||||
}
|
||||
+30
@@ -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.*"
|
||||
}
|
||||
+83
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -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.*"
|
||||
}
|
||||
+97
@@ -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}"
|
||||
}
|
||||
+93
@@ -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()
|
||||
)
|
||||
}
|
||||
+12
@@ -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>()
|
||||
}
|
||||
+26
@@ -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)
|
||||
}
|
||||
}
|
||||
+28
@@ -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
|
||||
}
|
||||
+47
@@ -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)
|
||||
+67
@@ -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
-16
@@ -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);
|
||||
|
||||
+43
@@ -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
|
||||
}
|
||||
-5
@@ -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);
|
||||
}
|
||||
|
||||
+17
@@ -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
-24
@@ -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() {
|
||||
|
||||
+13
-16
@@ -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;
|
||||
}
|
||||
|
||||
+11
-16
@@ -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");
|
||||
}
|
||||
|
||||
+3
-16
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+36
@@ -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)
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
|
||||
-219
@@ -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;
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -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);
|
||||
|
||||
+153
@@ -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
|
||||
}
|
||||
+4
-17
@@ -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));
|
||||
});
|
||||
|
||||
+7
-25
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-30
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-17
@@ -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 {
|
||||
|
||||
+179
@@ -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
|
||||
}
|
||||
}
|
||||
+9
-19
@@ -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 {}
|
||||
}
|
||||
+14
@@ -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 {}
|
||||
+27
@@ -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 {}
|
||||
+71
@@ -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()
|
||||
}
|
||||
}
|
||||
Vendored
+14
@@ -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 {}
|
||||
+14
@@ -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 {}
|
||||
Vendored
+27
@@ -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 {}
|
||||
+71
@@ -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()
|
||||
}
|
||||
}
|
||||
Vendored
+14
@@ -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 {}
|
||||
+14
@@ -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 {}
|
||||
Vendored
+27
@@ -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 {}
|
||||
+71
@@ -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()
|
||||
}
|
||||
}
|
||||
Vendored
+14
@@ -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 {}
|
||||
+14
@@ -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 {}
|
||||
Vendored
+27
@@ -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 {}
|
||||
+71
@@ -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()
|
||||
}
|
||||
}
|
||||
Vendored
+14
@@ -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 {}
|
||||
+14
@@ -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 {}
|
||||
+27
@@ -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 {}
|
||||
+71
@@ -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()
|
||||
}
|
||||
}
|
||||
Vendored
+14
@@ -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 {}
|
||||
+14
@@ -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 {}
|
||||
+27
@@ -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 {}
|
||||
+71
@@ -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
Reference in New Issue
Block a user