Fixed generic type references when read from cls files (IDEA-141230)

https://github.com/JetBrains/intellij-community/pull/273
This commit is contained in:
Sebastian Zarnekow
2015-06-09 15:35:12 +03:00
committed by Roman Shevchenko
parent 4b4671f860
commit 8c20a632da
4 changed files with 73 additions and 3 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* 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.
@@ -17,7 +17,6 @@ package com.intellij.psi.impl.compiled;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiSubstitutorImpl;
import com.intellij.psi.impl.ResolveScopeManager;
@@ -33,6 +32,7 @@ import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -143,7 +143,7 @@ public class ClsJavaCodeReferenceElementImpl extends ClsElementImpl implements P
final Map<PsiTypeParameter, PsiType> substitutionMap) {
final PsiClass containingClass = psiClass.getContainingClass();
if (containingClass != null && !containingClass.hasModifierProperty(PsiModifier.STATIC)) {
final String outerClassRef = StringUtil.getPackageName(canonicalText);
final String outerClassRef = getOuterClassRef(canonicalText);
final String[] classParameters = PsiNameHelper.getClassParametersText(outerClassRef);
final PsiType[] args = classParameters.length == 0 ? null : new ClsReferenceParameterListImpl(this, classParameters).getTypeArguments();
final PsiTypeParameter[] typeParameters = containingClass.getTypeParameters();
@@ -156,6 +156,27 @@ public class ClsJavaCodeReferenceElementImpl extends ClsElementImpl implements P
}
}
@NotNull
@Contract(pure = true)
private static String getOuterClassRef(String ref) {
int stack = 0;
for (int i = ref.length() - 1; i >= 0; i--) {
char c = ref.charAt(i);
switch (c) {
case '<':
stack--;
break;
case '>':
stack++;
break;
case '.':
if (stack == 0) return ref.substring(0, i);
}
}
return "";
}
@Override
@NotNull
public JavaResolveResult advancedResolve(boolean incompleteCode) {
@@ -22,7 +22,9 @@ import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiClassType
import com.intellij.psi.PsiMethod
import com.intellij.psi.impl.JavaPsiFacadeEx
import com.intellij.psi.impl.source.PsiFileImpl
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.searches.ClassInheritorsSearch
@@ -236,4 +238,51 @@ class TestCase {
assert method.hierarchicalMethodSignature.superSignatures.size() == 0
}
public void "test nested generic signature from binary"() {
myFixture.testDataPath = PathManagerEx.getTestDataPath() + "/libResolve/genericSignature"
myFixture.copyDirectoryToProject("", "lib")
PsiTestUtil.addLibrary(myModule, "lib", myFixture.tempDirFixture.getFile("").path, "lib");
def javaPsiFacade = JavaPsiFacadeEx.getInstanceEx(project)
def factory = javaPsiFacade.elementFactory
def parameterizedTypes = JavaPsiFacade.getInstance(project).findClass('pkg.ParameterizedTypes', GlobalSearchScope.allScope(project))
assert parameterizedTypes
def parameterP = parameterizedTypes.typeParameters[0]
assert parameterP.name == 'P'
def classInner = parameterizedTypes.innerClasses[0]
assert classInner.name == 'Inner'
def parameterI = classInner.typeParameters[0]
assert parameterI.name == 'I'
def unspecificMethod = parameterizedTypes.findMethodsByName("getUnspecificInner", false)[0]
def unspecificReturnType = unspecificMethod.returnType as PsiClassType
assert unspecificReturnType.canonicalText == 'pkg.ParameterizedTypes<P>.Inner<java.lang.String>'
def unspecificResolveResult = unspecificReturnType.resolveGenerics()
assert unspecificResolveResult.element == classInner
def unspecificOuter = factory.createType(parameterizedTypes, unspecificResolveResult.substitutor);
assert unspecificOuter.canonicalText == 'pkg.ParameterizedTypes<P>'
def specificMethod = parameterizedTypes.findMethodsByName("getSpecificInner", false)[0]
def specificReturnType = specificMethod.returnType as PsiClassType
assert specificReturnType.canonicalText == 'pkg.ParameterizedTypes<java.lang.Number>.Inner<java.lang.String>'
def specificResolveResult = specificReturnType.resolveGenerics()
assert specificResolveResult.element == classInner
def substitutor = specificResolveResult.substitutor
def substitutionMap = substitutor.substitutionMap
assert substitutionMap.containsKey(parameterI)
assert substitutionMap.containsKey(parameterP)
assert substitutor.substitute(parameterP).canonicalText == 'java.lang.Number'
def specificOuter = factory.createType(parameterizedTypes, specificResolveResult.substitutor);
assert specificOuter.canonicalText == 'pkg.ParameterizedTypes<java.lang.Number>'
}
}