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.plugin.project.AnalyzerFacadeWithCache
import org.jetbrains.jet.plugin.JetBundle
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaNamespaceDescriptor
public object JetUsageTypeProvider : UsageTypeProviderEx {
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? {
if (element == null) return null
val simpleName = element?.getParentByType(javaClass<JetSimpleNameExpression>())
if (simpleName == null) return null
fun getCommonUsageType(): UsageType? {
return when {
element.getParentByType(javaClass<JetImportDirective>()) != null ->
simpleName.getParentByType(javaClass<JetImportDirective>()) != null ->
UsageType.CLASS_IMPORT
element.getParentByTypeAndBranch(javaClass<JetCallableReferenceExpression>()) { getCallableReference() } != null ->
simpleName.getParentByTypeAndBranch(javaClass<JetCallableReferenceExpression>()) { getCallableReference() } != null ->
JetUsageTypes.CALLABLE_REFERENCE
else -> null
}
}
fun getClassUsageType(): UsageType? {
val property = element.getParentByType(javaClass<JetProperty>())
val property = simpleName.getParentByType(javaClass<JetProperty>())
if (property != null) {
when {
property.getTypeRef().isAncestor(element) ->
property.getTypeRef().isAncestor(simpleName) ->
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
}
}
val function = element.getParentByType(javaClass<JetFunction>())
val function = simpleName.getParentByType(javaClass<JetFunction>())
if (function != null) {
when {
function.getReturnTypeRef().isAncestor(element) ->
function.getReturnTypeRef().isAncestor(simpleName) ->
return JetUsageTypes.FUNCTION_RETURN_TYPE
function.getReceiverTypeRef().isAncestor(element) ->
function.getReceiverTypeRef().isAncestor(simpleName) ->
return JetUsageTypes.EXTENSION_RECEIVER_TYPE
}
}
return when {
element.getParentByTypeAndBranch(javaClass<JetTypeParameter>()) { getExtendsBound() } != null
|| element.getParentByTypeAndBranch(javaClass<JetTypeConstraint>()) { getBoundTypeReference() } != null ->
simpleName.getParentByTypeAndBranch(javaClass<JetTypeParameter>()) { getExtendsBound() } != null
|| simpleName.getParentByTypeAndBranch(javaClass<JetTypeConstraint>()) { getBoundTypeReference() } != null ->
JetUsageTypes.TYPE_CONSTRAINT
element is JetDelegationSpecifier
|| element.getParentByTypeAndBranch(javaClass<JetDelegationSpecifier>()) { getTypeReference() } != null ->
simpleName is JetDelegationSpecifier
|| simpleName.getParentByTypeAndBranch(javaClass<JetDelegationSpecifier>()) { getTypeReference() } != null ->
JetUsageTypes.SUPER_TYPE
element.getParentByTypeAndBranch(javaClass<JetTypedef>()) { getTypeReference() } != null ->
simpleName.getParentByTypeAndBranch(javaClass<JetTypedef>()) { getTypeReference() } != null ->
JetUsageTypes.TYPE_DEFINITION
element.getParentByType(javaClass<JetTypeProjection>()) != null ->
simpleName.getParentByType(javaClass<JetTypeProjection>()) != null ->
UsageType.TYPE_PARAMETER
element.getParentByTypeAndBranch(javaClass<JetParameter>()) { getTypeReference() } != null ->
simpleName.getParentByTypeAndBranch(javaClass<JetParameter>()) { getTypeReference() } != null ->
JetUsageTypes.VALUE_PARAMETER_TYPE
element.getParentByTypeAndBranch(javaClass<JetIsExpression>()) { getTypeRef() } != null ->
simpleName.getParentByTypeAndBranch(javaClass<JetIsExpression>()) { getTypeRef() } != null ->
JetUsageTypes.IS
with(element.getParentByTypeAndBranch(javaClass<JetBinaryExpressionWithTypeRHS>()) { getRight() }) {
with(simpleName.getParentByTypeAndBranch(javaClass<JetBinaryExpressionWithTypeRHS>()) { getRight() }) {
val opType = this?.getOperationReference()?.getReferencedNameElementType()
opType == JetTokens.AS_KEYWORD || opType == JetTokens.AS_SAFE
} ->
UsageType.CLASS_CAST_TO
with(element.getParentByTypeAndBranch(javaClass<JetDotQualifiedExpression>()) { getReceiverExpression() }) {
this?.getReceiverExpression() is JetSimpleNameExpression
with(simpleName.getParentByType(javaClass<JetDotQualifiedExpression>())) {
if (this == null) false
else if (getReceiverExpression() == simpleName) true
else
getSelectorExpression() == simpleName
&& getParentByTypeAndBranch(javaClass<JetDotQualifiedExpression>(), true) { getReceiverExpression() } != null
} ->
JetUsageTypes.CLASS_OBJECT_ACCESS
element.getParentByTypeAndBranch(javaClass<JetSuperExpression>()) { getSuperTypeQualifier() } != null ->
simpleName.getParentByTypeAndBranch(javaClass<JetSuperExpression>()) { getSuperTypeQualifier() } != null ->
JetUsageTypes.SUPER_TYPE_QUALIFIER
else -> null
@@ -112,30 +118,30 @@ public object JetUsageTypeProvider : UsageTypeProviderEx {
}
fun getVariableUsageType(): UsageType? {
if (element.getParentByTypeAndBranch(javaClass<JetDelegatorByExpressionSpecifier>()) { getDelegateExpression() } != null) {
if (simpleName.getParentByTypeAndBranch(javaClass<JetDelegatorByExpressionSpecifier>()) { getDelegateExpression() } != null) {
return JetUsageTypes.DELEGATE
}
val dotQualifiedExpression = element.getParentByType(javaClass<JetDotQualifiedExpression>())
val dotQualifiedExpression = simpleName.getParentByType(javaClass<JetDotQualifiedExpression>())
if (dotQualifiedExpression != null) {
val parent = dotQualifiedExpression.getParent()
when {
dotQualifiedExpression.getReceiverExpression().isAncestor(element) ->
dotQualifiedExpression.getReceiverExpression().isAncestor(simpleName) ->
return JetUsageTypes.RECEIVER
parent is JetDotQualifiedExpression && parent.getReceiverExpression().isAncestor(element) ->
parent is JetDotQualifiedExpression && parent.getReceiverExpression().isAncestor(simpleName) ->
return JetUsageTypes.RECEIVER
}
}
return when {
element.getParentByTypeAndPredicate(
simpleName.getParentByTypeAndPredicate(
javaClass<JetBinaryExpression>(), false, { JetPsiUtil.isAssignment(it) }
)?.getLeft().isAncestor(element) ->
)?.getLeft().isAncestor(simpleName) ->
UsageType.WRITE
element.getParentByType(javaClass<JetSimpleNameExpression>()) != null ->
simpleName.getParentByType(javaClass<JetSimpleNameExpression>()) != null ->
UsageType.READ
else -> null
@@ -144,14 +150,14 @@ public object JetUsageTypeProvider : UsageTypeProviderEx {
fun getFunctionUsageType(descriptor: FunctionDescriptor): UsageType? {
return when {
element.getParentByTypeAndBranch(javaClass<JetDelegationSpecifier>()) { getTypeReference() } != null ->
simpleName.getParentByTypeAndBranch(javaClass<JetDelegationSpecifier>()) { getTypeReference() } != null ->
JetUsageTypes.SUPER_TYPE
descriptor is ConstructorDescriptor
&& element.getParentByTypeAndBranch(javaClass<JetAnnotationEntry>()) { getTypeReference() } != null ->
&& simpleName.getParentByTypeAndBranch(javaClass<JetAnnotationEntry>()) { getTypeReference() } != null ->
UsageType.ANNOTATION
with(element.getParentByTypeAndBranch(javaClass<JetCallExpression>()) { getCalleeExpression() }) {
with(simpleName.getParentByTypeAndBranch(javaClass<JetCallExpression>()) { getCalleeExpression() }) {
this?.getCalleeExpression() is JetSimpleNameExpression
} ->
if (descriptor is ConstructorDescriptor) UsageType.CLASS_NEW_OPERATOR else JetUsageTypes.FUNCTION_CALL
@@ -163,17 +169,17 @@ public object JetUsageTypeProvider : UsageTypeProviderEx {
val usageType = getCommonUsageType()
if (usageType != null) return usageType
val reference = element.getParentByType(javaClass<JetSimpleNameExpression>())
val reference = simpleName.getParentByType(javaClass<JetSimpleNameExpression>())
if (reference == null) return null
val file = element.getContainingFile()
val file = simpleName.getContainingFile()
if (file == null) return null
val bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache(file as JetFile).getBindingContext()
val descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, reference)
return when (descriptor) {
is ClassifierDescriptor -> getClassUsageType()
is ClassifierDescriptor, is JavaNamespaceDescriptor -> getClassUsageType()
is VariableDescriptor -> getVariableUsageType()
is FunctionDescriptor -> getFunctionUsageType(descriptor)
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 (36: 16) fun Any.toA(): 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 (32: 18) fun X.bar(a: 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 (28: 11) object O: A() {
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