-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #11 from Roenke/fix-illegal-access-errors
Fix illegal access errors when trace expression evaluating
- Loading branch information
Showing
28 changed files
with
745 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
src/main/java/com/intellij/debugger/streams/psi/PsiElementTransformer.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.intellij.debugger.streams.psi | ||
|
||
import com.intellij.psi.PsiElement | ||
import com.intellij.psi.PsiElementVisitor | ||
|
||
/** | ||
* @author Vitaliy.Bibaev | ||
*/ | ||
interface PsiElementTransformer { | ||
fun transform(element: PsiElement): Unit | ||
|
||
abstract class Base: PsiElementTransformer { | ||
override fun transform(element: PsiElement) { | ||
element.accept(visitor) | ||
} | ||
|
||
protected abstract val visitor: PsiElementVisitor | ||
} | ||
} |
175 changes: 175 additions & 0 deletions
175
src/main/java/com/intellij/debugger/streams/psi/impl/LambdaToAnonymousTransformer.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
package com.intellij.debugger.streams.psi.impl | ||
|
||
import com.intellij.codeInsight.ChangeContextUtil | ||
import com.intellij.codeInsight.generation.GenerateMembersUtil | ||
import com.intellij.codeInsight.generation.OverrideImplementUtil.* | ||
import com.intellij.codeInsight.generation.PsiGenerationInfo | ||
import com.intellij.debugger.streams.psi.PsiElementTransformer | ||
import com.intellij.openapi.diagnostic.Logger | ||
import com.intellij.psi.* | ||
import com.intellij.psi.util.* | ||
import com.intellij.refactoring.util.RefactoringChangeUtil | ||
import java.util.* | ||
|
||
/** | ||
* Copied with minor changes from: LambdaCanBeReplacedWithAnonymousInspection | ||
* Cannot reuse because the call OverrideImplementUtil.overrideOrImplement require a VirtualFile | ||
* | ||
* @author Vitaliy.Bibaev | ||
*/ | ||
object LambdaToAnonymousTransformer : PsiElementTransformer.Base() { | ||
val LOG = Logger.getInstance("#" + LambdaToAnonymousTransformer::class.java.name) | ||
|
||
override val visitor: PsiElementVisitor | ||
get() = object : JavaRecursiveElementVisitor() { | ||
override fun visitLambdaExpression(lambdaExpression: PsiLambdaExpression?) { | ||
if (lambdaExpression == null || !isConvertible(lambdaExpression)) return | ||
val paramListCopy = (lambdaExpression.parameterList.copy() as PsiParameterList).parameters | ||
val functionalInterfaceType = lambdaExpression.functionalInterfaceType ?: return | ||
val method = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType) ?: return | ||
|
||
val blockText = getBodyText(lambdaExpression) ?: return | ||
|
||
val project = lambdaExpression.project | ||
val psiElementFactory = JavaPsiFacade.getElementFactory(project) | ||
var blockFromText = psiElementFactory.createCodeBlockFromText(blockText, lambdaExpression) | ||
qualifyThisExpressions(lambdaExpression, psiElementFactory, blockFromText) | ||
blockFromText = psiElementFactory.createCodeBlockFromText(blockFromText.text, null) | ||
|
||
var newExpression = psiElementFactory.createExpressionFromText("new " + functionalInterfaceType.canonicalText + "(){}", | ||
lambdaExpression) as PsiNewExpression | ||
newExpression = lambdaExpression.replace(newExpression) as PsiNewExpression | ||
|
||
val anonymousClass = newExpression.anonymousClass | ||
LOG.assertTrue(anonymousClass != null) | ||
val infos = overrideOrImplement(anonymousClass!!, method) | ||
if (infos.size == 1) { | ||
val member = infos[0].psiMember | ||
val parameters = member.parameterList.parameters | ||
if (parameters.size == paramListCopy.size) { | ||
for (i in parameters.indices) { | ||
val parameter = parameters[i] | ||
val lambdaParamName = paramListCopy[i].name | ||
if (lambdaParamName != null) { | ||
parameter.setName(lambdaParamName) | ||
} | ||
} | ||
} | ||
val codeBlock = member.body | ||
LOG.assertTrue(codeBlock != null) | ||
codeBlock!!.replace(blockFromText) | ||
|
||
val parent = anonymousClass.parent.parent | ||
if (parent is PsiTypeCastExpression && RedundantCastUtil.isCastRedundant(parent)) { | ||
val operand = parent.operand | ||
LOG.assertTrue(operand != null) | ||
parent.replace(operand!!) | ||
} | ||
} | ||
} | ||
} | ||
|
||
private fun overrideOrImplement(psiClass: PsiAnonymousClass, baseMethod: PsiMethod): List<PsiGenerationInfo<PsiMethod>> { | ||
val prototypes = convert2GenerationInfos(overrideOrImplementMethod(psiClass, baseMethod, false)) | ||
if (prototypes.isEmpty()) return emptyList() | ||
|
||
val substitutor = TypeConversionUtil.getSuperClassSubstitutor(baseMethod.containingClass!!, psiClass, PsiSubstitutor.EMPTY) | ||
val anchor = getDefaultAnchorToOverrideOrImplement(psiClass, baseMethod, substitutor) | ||
return GenerateMembersUtil.insertMembersBeforeAnchor<PsiGenerationInfo<PsiMethod>>(psiClass, anchor, prototypes) | ||
} | ||
|
||
private fun getBodyText(lambda: PsiLambdaExpression): String? { | ||
var blockText: String? | ||
val body = lambda.body | ||
if (body is PsiExpression) { | ||
val returnType = LambdaUtil.getFunctionalInterfaceReturnType(lambda) | ||
blockText = "{" | ||
blockText += if (PsiType.VOID == returnType) "" else "return " | ||
blockText += body.text + ";}" | ||
} | ||
else if (body != null) { | ||
blockText = body.text | ||
} | ||
else { | ||
blockText = null | ||
} | ||
return blockText | ||
} | ||
|
||
private fun qualifyThisExpressions(lambdaExpression: PsiLambdaExpression, | ||
psiElementFactory: PsiElementFactory, | ||
blockFromText: PsiCodeBlock): Unit { | ||
ChangeContextUtil.encodeContextInfo(blockFromText, true) | ||
val thisClass = RefactoringChangeUtil.getThisClass(lambdaExpression) | ||
val thisClassName = if (thisClass != null && thisClass !is PsiSyntheticClass) thisClass.name else null | ||
if (thisClassName != null) { | ||
val thisAccessExpr = RefactoringChangeUtil.createThisExpression(lambdaExpression.manager, thisClass) | ||
ChangeContextUtil.decodeContextInfo(blockFromText, thisClass, thisAccessExpr) | ||
val replacements = HashSet<PsiExpression>() | ||
blockFromText.accept(object : JavaRecursiveElementWalkingVisitor() { | ||
override fun visitClass(aClass: PsiClass) {} | ||
|
||
override fun visitSuperExpression(expression: PsiSuperExpression) { | ||
super.visitSuperExpression(expression) | ||
if (expression.qualifier == null) { | ||
replacements.add(expression) | ||
} | ||
} | ||
|
||
override fun visitMethodCallExpression(expression: PsiMethodCallExpression) { | ||
super.visitMethodCallExpression(expression) | ||
if (thisAccessExpr != null) { | ||
val psiMethod = expression.resolveMethod() | ||
val methodExpression = expression.methodExpression | ||
if (psiMethod != null && !psiMethod.hasModifierProperty(PsiModifier.STATIC) && methodExpression.qualifierExpression == null) { | ||
replacements.add(expression) | ||
} | ||
} | ||
} | ||
}) | ||
for (expression in replacements) { | ||
if (expression is PsiSuperExpression) { | ||
expression.replace(psiElementFactory.createExpressionFromText(thisClassName + "." + expression.getText(), expression)) | ||
} | ||
else if (expression is PsiMethodCallExpression) { | ||
expression.methodExpression.qualifierExpression = thisAccessExpr | ||
} | ||
else { | ||
LOG.error("Unexpected expression") | ||
} | ||
} | ||
} | ||
} | ||
|
||
private fun isConvertible(lambdaExpression: PsiLambdaExpression): Boolean { | ||
val thisClass = PsiTreeUtil.getParentOfType(lambdaExpression, PsiClass::class.java, true) | ||
if (thisClass == null || thisClass is PsiAnonymousClass) { | ||
val body = lambdaExpression.body ?: return false | ||
val disabled = BooleanArray(1) | ||
body.accept(object : JavaRecursiveElementWalkingVisitor() { | ||
override fun visitThisExpression(expression: PsiThisExpression) { | ||
disabled[0] = true | ||
} | ||
|
||
override fun visitSuperExpression(expression: PsiSuperExpression) { | ||
disabled[0] = true | ||
} | ||
}) | ||
if (disabled[0]) return false | ||
} | ||
val functionalInterfaceType = lambdaExpression.functionalInterfaceType | ||
if (functionalInterfaceType != null && | ||
LambdaUtil.isLambdaFullyInferred(lambdaExpression, functionalInterfaceType) && | ||
LambdaUtil.isFunctionalType(functionalInterfaceType)) { | ||
val interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType) | ||
if (interfaceMethod != null) { | ||
val substitutor = LambdaUtil.getSubstitutor(interfaceMethod, PsiUtil.resolveGenericsClassInType(functionalInterfaceType)) | ||
if (interfaceMethod.getSignature(substitutor).parameterTypes.any { !PsiTypesUtil.isDenotableType(it) }) return false | ||
val returnType = LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType) | ||
return PsiTypesUtil.isDenotableType(returnType) | ||
} | ||
} | ||
|
||
return false | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
src/main/java/com/intellij/debugger/streams/psi/impl/MethodReferenceToLambdaTransformer.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.intellij.debugger.streams.psi.impl | ||
|
||
import com.intellij.debugger.streams.psi.PsiElementTransformer | ||
import com.intellij.psi.JavaRecursiveElementVisitor | ||
import com.intellij.psi.PsiElementVisitor | ||
import com.intellij.psi.PsiMethodReferenceExpression | ||
import com.intellij.refactoring.util.LambdaRefactoringUtil | ||
|
||
/** | ||
* @author Vitaliy.Bibaev | ||
*/ | ||
object MethodReferenceToLambdaTransformer : PsiElementTransformer.Base() { | ||
override val visitor: PsiElementVisitor | ||
get() = object : JavaRecursiveElementVisitor() { | ||
override fun visitMethodReferenceExpression(expression: PsiMethodReferenceExpression?) { | ||
super.visitMethodReferenceExpression(expression) | ||
if (expression == null) return | ||
LambdaRefactoringUtil.convertMethodReferenceToLambda(expression, false, true) | ||
} | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
src/main/java/com/intellij/debugger/streams/psi/impl/ToObjectInheritorTransformer.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package com.intellij.debugger.streams.psi.impl | ||
|
||
import com.intellij.debugger.streams.psi.PsiElementTransformer | ||
import com.intellij.psi.JavaElementVisitor | ||
import com.intellij.psi.PsiElementVisitor | ||
|
||
/** | ||
* @author Vitaliy.Bibaev | ||
*/ | ||
object ToObjectInheritorTransformer: PsiElementTransformer.Base() { | ||
override val visitor: PsiElementVisitor | ||
get() = object : JavaElementVisitor() {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.