[groovy] fix direct inheritors search when aliased import is used

This commit is contained in:
Daniil Ovchinnikov
2016-05-05 15:43:28 +03:00
parent fd5015e44a
commit 6cc0a36607
3 changed files with 116 additions and 7 deletions
@@ -18,27 +18,32 @@ package org.jetbrains.plugins.groovy.lang.psi.stubs;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.PsiModifierList;
import com.intellij.psi.PsiModifierListOwner;
import com.intellij.psi.PsiNameHelper;
import com.intellij.psi.*;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.stubs.StubInputStream;
import com.intellij.psi.stubs.StubOutputStream;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
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.typedef.GrAnonymousClassDefinition;
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.GrTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrReferenceElementImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.modifiers.GrModifierListImpl;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* User: Dmitry.Krasilschikov
@@ -92,10 +97,45 @@ public class GrStubUtils {
return typeElement == null ? null : typeElement.getText();
}
@NotNull
private static Map<String, String> getAliasMapping(@Nullable PsiFile file) {
if (!(file instanceof GroovyFile)) return Collections.emptyMap();
return CachedValuesManager.getCachedValue(file, () -> {
Map<String, String> mapping = ContainerUtil.newHashMap();
for (GrImportStatement importStatement : ((GroovyFile)file).getImportStatements()) {
if (importStatement.getImportReference() != null && !importStatement.isStatic() && importStatement.isAliasedImport()) {
String importName = importStatement.getImportReference().getClassNameText();
String importedName = importStatement.getImportedName();
if (importedName != null) {
mapping.put(importedName, importName);
}
}
}
return CachedValueProvider.Result.create(mapping, file);
});
}
@Nullable
public static String getReferenceName(@NotNull GrReferenceElement element) {
final String referenceName = element.getReferenceName();
if (referenceName == null) return null;
// Foo -> java.util.List
final String mappedFqn = getAliasMapping(element.getContainingFile()).get(referenceName);
final String fullText = element instanceof GrReferenceElementImpl
? ((GrReferenceElementImpl)element).getTextSkipWhiteSpaceAndComments()
: element.getText();
// alias: Foo<String> -> java.util.List<String>
// unqualified ref: List<String> -> List<String>
// qualified ref: java.util.List<String> -> java.util.List<String>
return mappedFqn == null ? fullText : fullText.replace(referenceName, mappedFqn);
}
@Nullable
public static String getBaseClassName(@NotNull GrTypeDefinition psi) {
if (!(psi instanceof GrAnonymousClassDefinition)) return null;
return ((GrAnonymousClassDefinition)psi).getBaseClassReferenceGroovy().getReferenceName();
return getReferenceName(((GrAnonymousClassDefinition)psi).getBaseClassReferenceGroovy());
}
public static String[] getAnnotationNames(PsiModifierListOwner psi) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* 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.
@@ -46,7 +46,7 @@ public abstract class GrReferenceListElementType<T extends GrReferenceList> exte
public GrReferenceListStub createStub(@NotNull T psi, StubElement parentStub) {
List<String> refNames = new ArrayList<String>();
for (GrCodeReferenceElement element : psi.getReferenceElementsGroovy()) {
final String name = element.getText();
final String name = GrStubUtils.getReferenceName(element);
if (StringUtil.isNotEmpty(name)) {
refNames.add(name);
}
@@ -0,0 +1,69 @@
/*
* 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.overriding
import com.intellij.psi.search.searches.DirectClassInheritorsSearch
import groovy.transform.CompileStatic
import org.jetbrains.plugins.groovy.LightGroovyTestCase
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition
@CompileStatic
class GrAliasedImportInheritorsTest extends LightGroovyTestCase {
final String basePath = null
void 'test aliased import'() {
def iface = myFixture.addClass '''
package pckg;
public interface MyInterface {}
'''
myFixture.addFileToProject 'a.groovy', """\
import pckg.MyInterface as Roo
class MyClass implements Roo {}
enum MyEnum implements Roo {}
trait MyTrait implements Roo {}
new Roo() {}
"""
def inheritors = DirectClassInheritorsSearch.search(iface).findAll()
assert inheritors.size() == 4
}
void 'test aliased import with generics'() {
def iface = myFixture.addClass '''
package pckg;
public interface MyInterface<T> {}
'''
myFixture.addFileToProject 'a.groovy', """\
import pckg.MyInterface as Roo
class MyClass implements Roo<String> {}
enum MyEnum implements Roo<Integer> {}
trait MyTrait implements Roo<Long> {}
new Roo<Double>() {}
"""
def inheritors = DirectClassInheritorsSearch.search(iface).findAll()
assert inheritors.size() == 4
inheritors.each {
def type = (it as GrTypeDefinition).getImplementsListTypes(false).first()
def resolveResult = type.resolveGenerics()
assert resolveResult.element == iface
assert resolveResult.substitutor.substitute(iface.typeParameters.first())
}
}
}