-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
KE2: Extract String.plus
and String?.plus
calls
#17752
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,13 @@ import org.jetbrains.kotlin.analysis.api.resolution.KaSuccessCallInfo | |
import org.jetbrains.kotlin.analysis.api.resolution.symbol | ||
import org.jetbrains.kotlin.analysis.api.symbols.KaFunctionSymbol | ||
import org.jetbrains.kotlin.analysis.api.types.KaType | ||
import org.jetbrains.kotlin.analysis.api.types.KaTypeNullability | ||
import org.jetbrains.kotlin.analysis.api.types.symbol | ||
import org.jetbrains.kotlin.lexer.KtTokens | ||
import org.jetbrains.kotlin.name.CallableId | ||
import org.jetbrains.kotlin.name.ClassId | ||
import org.jetbrains.kotlin.name.FqName | ||
import org.jetbrains.kotlin.name.Name | ||
import org.jetbrains.kotlin.parsing.parseNumericLiteral | ||
import org.jetbrains.kotlin.psi.* | ||
|
||
|
@@ -215,25 +221,57 @@ OLD: KE1 | |
} | ||
*/ | ||
|
||
private fun isFunction( | ||
private fun isFunctionMatchingNames( | ||
symbol: KaFunctionSymbol, | ||
name: CallableId, | ||
isExtension: Boolean = false, | ||
nullability: KaTypeNullability = KaTypeNullability.UNKNOWN, | ||
extensionReceiverClassName: ClassId? = null | ||
): Boolean { | ||
|
||
if (symbol.callableId != name) | ||
return false | ||
|
||
if (!isExtension) | ||
return true | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a bit confused what's going on here. Should this be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I reworked this a bit in an extra commit. My goal was to only use the last two parameters if |
||
|
||
val receiverType = symbol.receiverParameter?.type | ||
if (receiverType == null) | ||
return false | ||
|
||
if (receiverType.nullability != nullability) | ||
return false | ||
|
||
if (receiverType.symbol?.classId != extensionReceiverClassName) | ||
return false | ||
|
||
return true | ||
} | ||
|
||
private fun isFunctionMatchingName( | ||
symbol: KaFunctionSymbol, | ||
packageName: String, | ||
className: String, | ||
className: String?, | ||
functionName: String | ||
): Boolean { | ||
|
||
return symbol.callableId?.packageName?.asString() == packageName && | ||
symbol.callableId?.className?.asString() == className && | ||
symbol.callableId?.callableName?.asString() == functionName | ||
return isFunctionMatchingNames( | ||
symbol, | ||
CallableId( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that it would be better to avoid constructing anything from kotlinc if possible, especially if we are aiming to use concurrency, as then we don't have to worry about what side-effects etc there might be. Here I think we can just as easily destruct the CallableId at the other end, as construct it here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've just been looking at how we might handle this problem in general; I'm more interested in cases where we want to extract e.g. a generated function, for which the analysis API doesn't give us the AST and we have to fabricate it. I was hoping that we could have our own CodeQlFunction interface, and have it be implemented by KtFunction using something like delegates. However, it looks like that isn't possible; there have long been discussions and proposals (e.g. https://youtrack.jetbrains.com/issue/KT-505, Kotlin/KEEP#87) but no implementation yet. Perhaps |
||
FqName(packageName), | ||
if (className == null) null else FqName(className), | ||
Name.identifier(functionName) | ||
) | ||
) | ||
} | ||
|
||
private fun isNumericFunction(target: KaFunctionSymbol, fName: String): Boolean { | ||
return isFunction(target, "kotlin", "Int", fName) || | ||
isFunction(target, "kotlin", "Byte", fName) || | ||
isFunction(target, "kotlin", "Short", fName) || | ||
isFunction(target, "kotlin", "Long", fName) || | ||
isFunction(target, "kotlin", "Float", fName) || | ||
isFunction(target, "kotlin", "Double", fName) | ||
private fun isNumericFunction(target: KaFunctionSymbol, functionName: String): Boolean { | ||
return isFunctionMatchingName(target, "kotlin", "Int", functionName) || | ||
isFunctionMatchingName(target, "kotlin", "Byte", functionName) || | ||
isFunctionMatchingName(target, "kotlin", "Short", functionName) || | ||
isFunctionMatchingName(target, "kotlin", "Long", functionName) || | ||
isFunctionMatchingName(target, "kotlin", "Float", functionName) || | ||
isFunctionMatchingName(target, "kotlin", "Double", functionName) | ||
} | ||
|
||
/** | ||
|
@@ -267,7 +305,16 @@ private fun KotlinFileExtractor.extractBinaryExpression( | |
TODO() | ||
} | ||
|
||
if (isNumericFunction(target, "plus")) { | ||
if (isNumericFunction(target, "plus") || | ||
isFunctionMatchingName(target, "kotlin", "String", "plus") || | ||
isFunctionMatchingNames( | ||
target, | ||
CallableId(FqName("kotlin"), null, Name.identifier("plus")), | ||
isExtension = true, | ||
nullability = KaTypeNullability.NULLABLE, | ||
ClassId(FqName("kotlin"), Name.identifier("String")) | ||
) | ||
) { | ||
val id = tw.getFreshIdLabel<DbAddexpr>() | ||
val type = useType(expression.expressionType) | ||
val exprParent = parent.expr(expression, callable) | ||
|
@@ -278,7 +325,7 @@ private fun KotlinFileExtractor.extractBinaryExpression( | |
extractExpressionExpr(expression.left!!, callable, id, 0, exprParent.enclosingStmt) | ||
extractExpressionExpr(expression.right!!, callable, id, 1, exprParent.enclosingStmt) | ||
} else { | ||
TODO() | ||
TODO("Extract as method call") | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was wondering if this would read more clearly as an extension, so you'd have
symbol.isFunctionMatchingNames(name, isExtension, nullability, extensionReceiverClassName)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I pushed an extra commit that changed the functions to extensions.