-
Notifications
You must be signed in to change notification settings - Fork 1.8k
KE2: Extract binary plus on numeric types #17729
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
Changes from all commits
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 |
---|---|---|
|
@@ -3,6 +3,10 @@ package com.github.codeql | |
import com.github.codeql.KotlinFileExtractor.StmtExprParent | ||
import org.jetbrains.kotlin.KtNodeTypes | ||
import org.jetbrains.kotlin.analysis.api.KaSession | ||
import org.jetbrains.kotlin.analysis.api.resolution.KaSimpleFunctionCall | ||
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.lexer.KtTokens | ||
import org.jetbrains.kotlin.parsing.parseNumericLiteral | ||
|
@@ -211,6 +215,78 @@ OLD: KE1 | |
} | ||
*/ | ||
|
||
private fun isFunction( | ||
symbol: KaFunctionSymbol, | ||
packageName: String, | ||
className: String, | ||
functionName: String | ||
): Boolean { | ||
|
||
return symbol.callableId?.packageName?.asString() == packageName && | ||
symbol.callableId?.className?.asString() == className && | ||
symbol.callableId?.callableName?.asString() == 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) | ||
} | ||
|
||
/** | ||
* Extracts a binary expression as either a binary expression or a function call. | ||
* | ||
* Overloaded operators are extracted as function calls. | ||
* | ||
* ``` | ||
* data class Counter(val dayIndex: Int) { | ||
* operator fun plus(increment: Int): Counter { | ||
* return Counter(dayIndex + increment) | ||
* } | ||
* } | ||
* ``` | ||
* | ||
* `Counter(1) + 3` is extracted as `Counter(1).plus(3)`. | ||
* | ||
*/ | ||
context(KaSession) | ||
private fun KotlinFileExtractor.extractBinaryExpression( | ||
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 a doc comment here would be useful, saying that sometimes these map to primitives like DbAddExpr, whereas at other times they are overloads (and give an example of how an overload of plus is defined in Kotlin). |
||
expression: KtBinaryExpression, | ||
callable: Label<out DbCallable>, | ||
parent: StmtExprParent | ||
) { | ||
val op = expression.operationToken | ||
val target = ((expression.resolveToCall() as? KaSuccessCallInfo)?.call as? KaSimpleFunctionCall)?.symbol | ||
|
||
when (op) { | ||
KtTokens.PLUS -> { | ||
if (target == null) { | ||
TODO() | ||
} | ||
|
||
if (isNumericFunction(target, "plus")) { | ||
val id = tw.getFreshIdLabel<DbAddexpr>() | ||
val type = useType(expression.expressionType) | ||
val exprParent = parent.expr(expression, callable) | ||
tw.writeExprs_addexpr(id, type.javaResult.id, exprParent.parent, exprParent.idx) | ||
tw.writeExprsKotlinType(id, type.kotlinResult.id) | ||
|
||
extractExprContext(id, tw.getLocation(expression), callable, exprParent.enclosingStmt) | ||
extractExpressionExpr(expression.left!!, callable, id, 0, exprParent.enclosingStmt) | ||
extractExpressionExpr(expression.right!!, callable, id, 1, exprParent.enclosingStmt) | ||
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. Aren't we going to want to do these 3 lines in every case, after the 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 don't know, maybe. In many cases 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. Ah, good point. Maybe best to leave it as-is for now and possibly refactor later. |
||
} else { | ||
TODO() | ||
} | ||
} | ||
|
||
else -> TODO() | ||
} | ||
|
||
} | ||
|
||
context(KaSession) | ||
private fun KotlinFileExtractor.extractExpression( | ||
e: KtExpression, | ||
|
@@ -225,6 +301,10 @@ private fun KotlinFileExtractor.extractExpression( | |
extractExpression(e.baseExpression!!, callable, parent) | ||
} | ||
|
||
is KtBinaryExpression -> { | ||
extractBinaryExpression(e, callable, parent) | ||
} | ||
|
||
is KtIsExpression -> { | ||
|
||
val locId = tw.getLocation(e) | ||
|
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 wonder if something like
isFunctionNamed
would be clearer. And maybe add a comment(I'm not sure if I have the best punctuation in
packageName.className::functionName
OTTOMH)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.
The KE1 equivalent of this function has some extra parameters, such as nullability, so adding
Named
would not necessarily make sense.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.
OK; I don't like the name
isFunction
, because it sounds like it tells you whether something is a function or something else (e.g. a class), but perhaps it's too early to pick the best name.