Error while executing EncapsulateFieldsProcessor

Answered

Hello. I want to build a plugin that finds fields and encapsulate them (hide field and generate getter,setter, replacing direct access to getter, setter).

I found that Intellij IDEA has a nice functionality called "Encapsulate Fields"

It hides variable field and replace field usages(direct access) to getter / setter.But because it works only on single file, I wanted to make it work on multiple files.

To accomplish this, I wrote codes below:

Action class:

ApplicationManager.getApplication().executeOnPooledThread {
val psiFiles = ApplicationManager.getApplication().runReadAction<List<PsiFile>> {
FilenameIndex.getAllFilesByExt(project, "java")
.filter { !it.isDirectory && it.path.startsWith(currentFile.path) }
.map { manager.findFile(it)!! }
}

val searchers = mutableSetOf<ClassSearcher>()

ProgressManager.getInstance().runInReadActionWithWriteActionPriority({
for (psiFile in psiFiles) {
progressWindow.text = "Searching class ${psiFile.name}"
val searcher = ClassSearcher(psiFile)
searcher.processSearch()
searchers.add(searcher)
}
}, progressWindow)
progressWindow.pushState()
ApplicationManager.getApplication().invokeLaterOnWriteThread({
for (searcher in searchers) {
try{
searcher.classes.forEach { cls ->
progressWindow.text = "Processing ${cls.name}"
val descriptor = ApplicationManager.getApplication().runReadAction<GSetterizableFieldDescriptor> { GSetterizableFieldDescriptor(cls) }
val processor = EncapsulateFieldsProcessor(project, descriptor)
processor.run()

}
}catch (e: ProcessCanceledException){
break
}
}
}, ModalityState.NON_MODAL)
}

These codes search java files under current location and classes. Also, creates simple implementation class of EncapsulateFieldsDescriptor,GSetterizableFieldsDescriptor, to create EncapsulateFieldProcessor instance.

code of GSetterizableFieldsDescriptor:

class GSetterizableFieldDescriptor(private val javaClass:PsiClass) : EncapsulateFieldsDescriptor {
private val fieldDescriptors:Array<FieldDescriptor> = javaClass.allFields.filter{ it.hasModifierProperty(PsiModifier.PUBLIC) }.map { SimpleFieldDescriptorImpl(it) }.toTypedArray()

override fun getSelectedFields(): Array<FieldDescriptor> = fieldDescriptors

override fun isToEncapsulateGet(): Boolean = true

override fun isToEncapsulateSet(): Boolean = true

override fun isToUseAccessorsWhenAccessible(): Boolean = true

override fun getFieldsVisibility(): String = PsiModifier.PRIVATE

override fun getAccessorsVisibility(): String = PsiModifier.PRIVATE


override fun getJavadocPolicy(): Int = DocCommentPolicy.COPY

override fun getTargetClass(): PsiClass = javaClass
}

and SimpleFieldDescriptorImpl to create FieldDescriptorImpl more efficiently:


class SimpleFieldDescriptorImpl(psiField: PsiField) : FieldDescriptorImpl(
psiField,
GenerateMembersUtil.suggestGetterName(psiField),
GenerateMembersUtil.suggestSetterName(psiField),
GenerateMembersUtil.generateGetterPrototype(psiField),
GenerateMembersUtil.generateSetterPrototype(psiField)
) {
}

But I got this error:

java.lang.IllegalArgumentException: Argument for @NotNull parameter 'newElement' of com/intellij/psi/impl/source/tree/CompositePsiElement.replace must not be null
    at com.intellij.psi.impl.source.tree.CompositePsiElement.$$$reportNull$$$0(CompositePsiElement.java)
    at com.intellij.psi.impl.source.tree.CompositePsiElement.replace(CompositePsiElement.java)
    at com.intellij.refactoring.encapsulateFields.JavaEncapsulateFieldHelper.processUsage(JavaEncapsulateFieldHelper.java:214)
    at com.intellij.refactoring.encapsulateFields.EncapsulateFieldsProcessor.processUsagesPerFile(EncapsulateFieldsProcessor.java:336)
    at com.intellij.refactoring.encapsulateFields.EncapsulateFieldsProcessor.performRefactoring(EncapsulateFieldsProcessor.java:271)
    at com.intellij.refactoring.BaseRefactoringProcessor.lambda$doRefactoring$10(BaseRefactoringProcessor.java:520)
    at com.intellij.refactoring.BaseRefactoringProcessor.callPerformRefactoring(BaseRefactoringProcessor.java:573)
    at com.intellij.refactoring.BaseRefactoringProcessor.lambda$doRefactoring$11(BaseRefactoringProcessor.java:519)
    at com.intellij.openapi.application.impl.ApplicationImpl.lambda$runEdtProgressWriteAction$9(ApplicationImpl.java:979)
    at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$2(CoreProgressManager.java:189)
    at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$executeProcessUnderProgress$12(CoreProgressManager.java:608)
    at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:683)
    at com.intellij.openapi.progress.impl.CoreProgressManager.computeUnderProgress(CoreProgressManager.java:639)
    at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:607)
    at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:60)
    at com.intellij.openapi.progress.impl.CoreProgressManager.runProcess(CoreProgressManager.java:176)
    at com.intellij.openapi.progress.util.PotemkinProgress.runInSwingThread(PotemkinProgress.java:164)
    at com.intellij.openapi.application.impl.ApplicationImpl.lambda$runEdtProgressWriteAction$10(ApplicationImpl.java:979)
    at com.intellij.openapi.application.impl.ApplicationImpl.runWriteActionWithClass(ApplicationImpl.java:1003)
    at com.intellij.openapi.application.impl.ApplicationImpl.runEdtProgressWriteAction(ApplicationImpl.java:977)
    at com.intellij.openapi.application.impl.ApplicationImpl.runWriteActionWithNonCancellableProgressInDispatchThread(ApplicationImpl.java:958)
    at com.intellij.refactoring.BaseRefactoringProcessor.doRefactoring(BaseRefactoringProcessor.java:518)
    at com.intellij.refactoring.BaseRefactoringProcessor.lambda$execute$2(BaseRefactoringProcessor.java:332)
    at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:219)
    at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:174)
    at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:164)
    at com.intellij.refactoring.BaseRefactoringProcessor.execute(BaseRefactoringProcessor.java:330)
    at com.intellij.refactoring.BaseRefactoringProcessor.doRun(BaseRefactoringProcessor.java:253)
    at com.intellij.util.SlowOperations.allowSlowOperations(SlowOperations.java:147)
    at com.intellij.refactoring.BaseRefactoringProcessor.lambda$run$19(BaseRefactoringProcessor.java:624)
    at com.intellij.refactoring.BaseRefactoringProcessor.run(BaseRefactoringProcessor.java:638)
    at io.github.singlerr.gsetterizer.actions.GSetterizeAction.actionPerformed$lambda-7$lambda-6(GSetterizeAction.kt:69)
    at com.intellij.openapi.application.TransactionGuardImpl.runWithWritingAllowed(TransactionGuardImpl.java:215)
    at com.intellij.openapi.application.TransactionGuardImpl.access$100(TransactionGuardImpl.java:22)
    at com.intellij.openapi.application.TransactionGuardImpl$1.run(TransactionGuardImpl.java:197)
    at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:873)
    at com.intellij.openapi.application.impl.ApplicationImpl$3.run(ApplicationImpl.java:511)
    at com.intellij.openapi.application.impl.FlushQueue.doRun(FlushQueue.java:69)
    at com.intellij.openapi.application.impl.FlushQueue.runNextEvent(FlushQueue.java:112)
    at com.intellij.openapi.application.impl.FlushQueue.flushNow(FlushQueue.java:42)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:776)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:746)
    at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:898)
    at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:746)
    at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:439)
    at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:803)
    at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:438)
    at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:106)
    at com.intellij.ide.IdeEventQueue.performActivity(IdeEventQueue.java:604)
    at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$8(IdeEventQueue.java:436)
    at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:873)
    at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:484)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:207)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:92)
2022-09-04 21:36:39,434 [ 150332] SEVERE - #c.i.o.a.i.FlushQueue - IntelliJ IDEA 2022.1  Build #IC-221.5080.210
2022-09-04 21:36:39,434 [ 150332] SEVERE - #c.i.o.a.i.FlushQueue - JDK: 11.0.14.1; VM: OpenJDK 64-Bit Server VM; Vendor: JetBrains s.r.o.
2022-09-04 21:36:39,434 [ 150332] SEVERE - #c.i.o.a.i.FlushQueue - OS: Windows 10
2022-09-04 21:36:39,435 [ 150333] SEVERE - #c.i.o.a.i.FlushQueue - Plugin to blame: GSetterizer version: 1.2-SNAPSHOT
2022-09-04 21:36:39,452 [ 150350]   WARN - #c.i.d.PerformanceWatcherImpl - UI was frozen for 6469ms, details saved to D:\ProjectStorage\IdeaProjects\GSetterizer\build\idea-sandbox\system\log\threadDumps-freeze-20220904-213637-IC-221.5080.210-6sec

 According to stacktrace, I found that JavaEncapsulateFieldHelper#checkMethodResolvable returns null. In that method, 

methodCall.getMethodExpression().resolve()

returns null.

It occurrs only specific variable fields, not all of fields. How can i fix this?

Thank you.

0
1 comment

Hm... I don't know this code pretty well but from what I see, you are creating the setters private (getAccessorsVisibility(): String = PsiModifier.PRIVATE) but you are encapsulating public fields (javaClass.allFields.filter{ it.hasModifierProperty(PsiModifier.PUBLIC) }...). If a public field is accessed from another file, and you replace this access with a private setter, it may not resolve anymore. How about returning PsiModifier.PUBLIC from getAccessorsVisibility()? Note that it's just a guess, I did not try to actually debug this code.

0

Please sign in to leave a comment.