Fix usage type detection for static members of Java classes and members of nested classes

This commit is contained in:
Alexey Sedunov
2013-11-01 18:33:59 +04:00
parent 40900ac16c
commit f99e6e6765
2 changed files with 44 additions and 38 deletions
@@ -31,6 +31,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lexer.JetTokens import org.jetbrains.jet.lexer.JetTokens
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
import org.jetbrains.jet.plugin.JetBundle import org.jetbrains.jet.plugin.JetBundle
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaNamespaceDescriptor
public object JetUsageTypeProvider : UsageTypeProviderEx { public object JetUsageTypeProvider : UsageTypeProviderEx {
public override fun getUsageType(element: PsiElement?): UsageType? { public override fun getUsageType(element: PsiElement?): UsageType? {
@@ -38,73 +39,78 @@ public object JetUsageTypeProvider : UsageTypeProviderEx {
} }
public override fun getUsageType(element: PsiElement?, targets: Array<out UsageTarget>): UsageType? { public override fun getUsageType(element: PsiElement?, targets: Array<out UsageTarget>): UsageType? {
if (element == null) return null val simpleName = element?.getParentByType(javaClass<JetSimpleNameExpression>())
if (simpleName == null) return null
fun getCommonUsageType(): UsageType? { fun getCommonUsageType(): UsageType? {
return when { return when {
element.getParentByType(javaClass<JetImportDirective>()) != null -> simpleName.getParentByType(javaClass<JetImportDirective>()) != null ->
UsageType.CLASS_IMPORT UsageType.CLASS_IMPORT
element.getParentByTypeAndBranch(javaClass<JetCallableReferenceExpression>()) { getCallableReference() } != null -> simpleName.getParentByTypeAndBranch(javaClass<JetCallableReferenceExpression>()) { getCallableReference() } != null ->
JetUsageTypes.CALLABLE_REFERENCE JetUsageTypes.CALLABLE_REFERENCE
else -> null else -> null
} }
} }
fun getClassUsageType(): UsageType? { fun getClassUsageType(): UsageType? {
val property = element.getParentByType(javaClass<JetProperty>()) val property = simpleName.getParentByType(javaClass<JetProperty>())
if (property != null) { if (property != null) {
when { when {
property.getTypeRef().isAncestor(element) -> property.getTypeRef().isAncestor(simpleName) ->
return if (property.isLocal()) UsageType.CLASS_LOCAL_VAR_DECLARATION else JetUsageTypes.NON_LOCAL_PROPERTY_TYPE return if (property.isLocal()) UsageType.CLASS_LOCAL_VAR_DECLARATION else JetUsageTypes.NON_LOCAL_PROPERTY_TYPE
property.getReceiverTypeRef().isAncestor(element) -> property.getReceiverTypeRef().isAncestor(simpleName) ->
return JetUsageTypes.EXTENSION_RECEIVER_TYPE return JetUsageTypes.EXTENSION_RECEIVER_TYPE
} }
} }
val function = element.getParentByType(javaClass<JetFunction>()) val function = simpleName.getParentByType(javaClass<JetFunction>())
if (function != null) { if (function != null) {
when { when {
function.getReturnTypeRef().isAncestor(element) -> function.getReturnTypeRef().isAncestor(simpleName) ->
return JetUsageTypes.FUNCTION_RETURN_TYPE return JetUsageTypes.FUNCTION_RETURN_TYPE
function.getReceiverTypeRef().isAncestor(element) -> function.getReceiverTypeRef().isAncestor(simpleName) ->
return JetUsageTypes.EXTENSION_RECEIVER_TYPE return JetUsageTypes.EXTENSION_RECEIVER_TYPE
} }
} }
return when { return when {
element.getParentByTypeAndBranch(javaClass<JetTypeParameter>()) { getExtendsBound() } != null simpleName.getParentByTypeAndBranch(javaClass<JetTypeParameter>()) { getExtendsBound() } != null
|| element.getParentByTypeAndBranch(javaClass<JetTypeConstraint>()) { getBoundTypeReference() } != null -> || simpleName.getParentByTypeAndBranch(javaClass<JetTypeConstraint>()) { getBoundTypeReference() } != null ->
JetUsageTypes.TYPE_CONSTRAINT JetUsageTypes.TYPE_CONSTRAINT
element is JetDelegationSpecifier simpleName is JetDelegationSpecifier
|| element.getParentByTypeAndBranch(javaClass<JetDelegationSpecifier>()) { getTypeReference() } != null -> || simpleName.getParentByTypeAndBranch(javaClass<JetDelegationSpecifier>()) { getTypeReference() } != null ->
JetUsageTypes.SUPER_TYPE JetUsageTypes.SUPER_TYPE
element.getParentByTypeAndBranch(javaClass<JetTypedef>()) { getTypeReference() } != null -> simpleName.getParentByTypeAndBranch(javaClass<JetTypedef>()) { getTypeReference() } != null ->
JetUsageTypes.TYPE_DEFINITION JetUsageTypes.TYPE_DEFINITION
element.getParentByType(javaClass<JetTypeProjection>()) != null -> simpleName.getParentByType(javaClass<JetTypeProjection>()) != null ->
UsageType.TYPE_PARAMETER UsageType.TYPE_PARAMETER
element.getParentByTypeAndBranch(javaClass<JetParameter>()) { getTypeReference() } != null -> simpleName.getParentByTypeAndBranch(javaClass<JetParameter>()) { getTypeReference() } != null ->
JetUsageTypes.VALUE_PARAMETER_TYPE JetUsageTypes.VALUE_PARAMETER_TYPE
element.getParentByTypeAndBranch(javaClass<JetIsExpression>()) { getTypeRef() } != null -> simpleName.getParentByTypeAndBranch(javaClass<JetIsExpression>()) { getTypeRef() } != null ->
JetUsageTypes.IS JetUsageTypes.IS
with(element.getParentByTypeAndBranch(javaClass<JetBinaryExpressionWithTypeRHS>()) { getRight() }) { with(simpleName.getParentByTypeAndBranch(javaClass<JetBinaryExpressionWithTypeRHS>()) { getRight() }) {
val opType = this?.getOperationReference()?.getReferencedNameElementType() val opType = this?.getOperationReference()?.getReferencedNameElementType()
opType == JetTokens.AS_KEYWORD || opType == JetTokens.AS_SAFE opType == JetTokens.AS_KEYWORD || opType == JetTokens.AS_SAFE
} -> } ->
UsageType.CLASS_CAST_TO UsageType.CLASS_CAST_TO
with(element.getParentByTypeAndBranch(javaClass<JetDotQualifiedExpression>()) { getReceiverExpression() }) { with(simpleName.getParentByType(javaClass<JetDotQualifiedExpression>())) {
this?.getReceiverExpression() is JetSimpleNameExpression if (this == null) false
else if (getReceiverExpression() == simpleName) true
else
getSelectorExpression() == simpleName
&& getParentByTypeAndBranch(javaClass<JetDotQualifiedExpression>(), true) { getReceiverExpression() } != null
} -> } ->
JetUsageTypes.CLASS_OBJECT_ACCESS JetUsageTypes.CLASS_OBJECT_ACCESS
element.getParentByTypeAndBranch(javaClass<JetSuperExpression>()) { getSuperTypeQualifier() } != null -> simpleName.getParentByTypeAndBranch(javaClass<JetSuperExpression>()) { getSuperTypeQualifier() } != null ->
JetUsageTypes.SUPER_TYPE_QUALIFIER JetUsageTypes.SUPER_TYPE_QUALIFIER
else -> null else -> null
@@ -112,30 +118,30 @@ public object JetUsageTypeProvider : UsageTypeProviderEx {
} }
fun getVariableUsageType(): UsageType? { fun getVariableUsageType(): UsageType? {
if (element.getParentByTypeAndBranch(javaClass<JetDelegatorByExpressionSpecifier>()) { getDelegateExpression() } != null) { if (simpleName.getParentByTypeAndBranch(javaClass<JetDelegatorByExpressionSpecifier>()) { getDelegateExpression() } != null) {
return JetUsageTypes.DELEGATE return JetUsageTypes.DELEGATE
} }
val dotQualifiedExpression = element.getParentByType(javaClass<JetDotQualifiedExpression>()) val dotQualifiedExpression = simpleName.getParentByType(javaClass<JetDotQualifiedExpression>())
if (dotQualifiedExpression != null) { if (dotQualifiedExpression != null) {
val parent = dotQualifiedExpression.getParent() val parent = dotQualifiedExpression.getParent()
when { when {
dotQualifiedExpression.getReceiverExpression().isAncestor(element) -> dotQualifiedExpression.getReceiverExpression().isAncestor(simpleName) ->
return JetUsageTypes.RECEIVER return JetUsageTypes.RECEIVER
parent is JetDotQualifiedExpression && parent.getReceiverExpression().isAncestor(element) -> parent is JetDotQualifiedExpression && parent.getReceiverExpression().isAncestor(simpleName) ->
return JetUsageTypes.RECEIVER return JetUsageTypes.RECEIVER
} }
} }
return when { return when {
element.getParentByTypeAndPredicate( simpleName.getParentByTypeAndPredicate(
javaClass<JetBinaryExpression>(), false, { JetPsiUtil.isAssignment(it) } javaClass<JetBinaryExpression>(), false, { JetPsiUtil.isAssignment(it) }
)?.getLeft().isAncestor(element) -> )?.getLeft().isAncestor(simpleName) ->
UsageType.WRITE UsageType.WRITE
element.getParentByType(javaClass<JetSimpleNameExpression>()) != null -> simpleName.getParentByType(javaClass<JetSimpleNameExpression>()) != null ->
UsageType.READ UsageType.READ
else -> null else -> null
@@ -144,14 +150,14 @@ public object JetUsageTypeProvider : UsageTypeProviderEx {
fun getFunctionUsageType(descriptor: FunctionDescriptor): UsageType? { fun getFunctionUsageType(descriptor: FunctionDescriptor): UsageType? {
return when { return when {
element.getParentByTypeAndBranch(javaClass<JetDelegationSpecifier>()) { getTypeReference() } != null -> simpleName.getParentByTypeAndBranch(javaClass<JetDelegationSpecifier>()) { getTypeReference() } != null ->
JetUsageTypes.SUPER_TYPE JetUsageTypes.SUPER_TYPE
descriptor is ConstructorDescriptor descriptor is ConstructorDescriptor
&& element.getParentByTypeAndBranch(javaClass<JetAnnotationEntry>()) { getTypeReference() } != null -> && simpleName.getParentByTypeAndBranch(javaClass<JetAnnotationEntry>()) { getTypeReference() } != null ->
UsageType.ANNOTATION UsageType.ANNOTATION
with(element.getParentByTypeAndBranch(javaClass<JetCallExpression>()) { getCalleeExpression() }) { with(simpleName.getParentByTypeAndBranch(javaClass<JetCallExpression>()) { getCalleeExpression() }) {
this?.getCalleeExpression() is JetSimpleNameExpression this?.getCalleeExpression() is JetSimpleNameExpression
} -> } ->
if (descriptor is ConstructorDescriptor) UsageType.CLASS_NEW_OPERATOR else JetUsageTypes.FUNCTION_CALL if (descriptor is ConstructorDescriptor) UsageType.CLASS_NEW_OPERATOR else JetUsageTypes.FUNCTION_CALL
@@ -163,17 +169,17 @@ public object JetUsageTypeProvider : UsageTypeProviderEx {
val usageType = getCommonUsageType() val usageType = getCommonUsageType()
if (usageType != null) return usageType if (usageType != null) return usageType
val reference = element.getParentByType(javaClass<JetSimpleNameExpression>()) val reference = simpleName.getParentByType(javaClass<JetSimpleNameExpression>())
if (reference == null) return null if (reference == null) return null
val file = element.getContainingFile() val file = simpleName.getContainingFile()
if (file == null) return null if (file == null) return null
val bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache(file as JetFile).getBindingContext() val bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache(file as JetFile).getBindingContext()
val descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, reference) val descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, reference)
return when (descriptor) { return when (descriptor) {
is ClassifierDescriptor -> getClassUsageType() is ClassifierDescriptor, is JavaNamespaceDescriptor -> getClassUsageType()
is VariableDescriptor -> getVariableUsageType() is VariableDescriptor -> getVariableUsageType()
is FunctionDescriptor -> getFunctionUsageType(descriptor) is FunctionDescriptor -> getFunctionUsageType(descriptor)
else -> null else -> null
@@ -2,6 +2,10 @@ Class/object property type (2: 15) var next: A? = A()
Function return types (15: 20) fun getNext(): A? { Function return types (15: 20) fun getNext(): A? {
Function return types (36: 16) fun Any.toA(): A? { Function return types (36: 16) fun Any.toA(): A? {
Local variable declaration (11: 17) val aa: A = a Local variable declaration (11: 17) val aa: A = a
Nested class/object (1: 31) public class X(bar: String? = A.BAR): A() {
Nested class/object (3: 26) val myBar: String? = A.BAR
Nested class/object (6: 9) A.BAR = ""
Nested class/object (7: 9) A.foos()
New instance creation (2: 20) var next: A? = A() New instance creation (2: 20) var next: A? = A()
New instance creation (32: 18) fun X.bar(a: A = A()) { New instance creation (32: 18) fun X.bar(a: A = A()) {
Parameter type (10: 16) fun foo(a: A) { Parameter type (10: 16) fun foo(a: A) {
@@ -11,8 +15,4 @@ Supertype (1: 39) public class X(bar: String? = A.BAR): A() {
Supertype (23: 19) class object: A() { Supertype (23: 19) class object: A() {
Supertype (28: 11) object O: A() { Supertype (28: 11) object O: A() {
Target type of 'is' operation (37: 24) return if (this is A) this as A else null Target type of 'is' operation (37: 24) return if (this is A) this as A else null
Unclassified usage (1: 31) public class X(bar: String? = A.BAR): A() {
Unclassified usage (3: 26) val myBar: String? = A.BAR
Unclassified usage (6: 9) A.BAR = ""
Unclassified usage (7: 9) A.foos()
Usage in cast target type (37: 35) return if (this is A) this as A else null Usage in cast target type (37: 35) return if (this is A) this as A else null