How do I get the methods generated in the PsiAugmentProvider to handle generics correctly
I'm now using LightMethodBuilder to add methods to some classes so they compile in idea, just like lombok does.
But the difference is, I didn't find the right way to handle generic inference,
This scenario is:
The method added using LightMethodBuilder is getChain(String chainId, ChainTypeReference<T> chainTypeReference)
The method's return value is SerialChainPipelineBuilder<T>.
After installing the plugin, everything looks fine, as shown in the next image
But when I use this method, generics fail to infer correctly, as follows
I also noticed that the idea plugin console was reporting an error when typing the first parameter
2024-01-26 21:50:40,534 [ 199831] SEVERE - #c.i.c.d.i.PassExecutorService - Parameter: PsiParameter:chainId; siblings: [PsiParameter:chainId]; ancestors: DummyHolder
java.lang.IllegalStateException: Parameter: PsiParameter:chainId; siblings: [PsiParameter:chainId]; ancestors: DummyHolder
at com.intellij.psi.impl.source.PsiParameterImpl.getDeclarationScope(PsiParameterImpl.java:244)
at com.intellij.codeInspection.i18n.NlsInfo.fromAnnotationContext(NlsInfo.java:194)
at com.intellij.codeInspection.i18n.NlsInfo.forExpression(NlsInfo.java:96)
at com.intellij.codeInspection.i18n.TitleCapitalizationInspection$1.getCapitalization(TitleCapitalizationInspection.java:81)
at com.intellij.codeInspection.i18n.TitleCapitalizationInspection$1.visitElement(TitleCapitalizationInspection.java:53)
at com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl.accept(PsiLiteralExpressionImpl.java:173)
at com.intellij.codeInsight.daemon.impl.InspectionRunner$InspectionProblemHolder.visitElement(InspectionRunner.java:531)
at com.intellij.codeInsight.daemon.impl.InspectionRunner.processContext(InspectionRunner.java:380)
at com.intellij.codeInsight.daemon.impl.InspectionRunner.lambda$inspect$4(InspectionRunner.java:159)
at com.intellij.codeInsight.daemon.impl.InspectionRunner.lambda$processInOrderAsync$10(InspectionRunner.java:334)
at com.intellij.openapi.application.impl.RwLockHolder.tryRunReadAction(RwLockHolder.kt:310)
at com.intellij.openapi.application.impl.ApplicationImpl.tryRunReadAction(ApplicationImpl.java:925)
at com.intellij.codeInsight.daemon.impl.InspectionRunner.lambda$processInOrderAsync$11(InspectionRunner.java:334)
at com.intellij.openapi.application.impl.ReadMostlyRWLock.executeByImpatientReader(ReadMostlyRWLock.java:199)
at com.intellij.openapi.application.impl.RwLockHolder.executeByImpatientReader(RwLockHolder.kt:478)
at com.intellij.openapi.application.impl.ApplicationImpl.executeByImpatientReader(ApplicationImpl.java:182)
at com.intellij.codeInsight.daemon.impl.InspectionRunner.lambda$processInOrderAsync$12(InspectionRunner.java:340)
at com.intellij.util.AstLoadingFilter.forceAllowTreeLoading(AstLoadingFilter.java:158)
at com.intellij.util.AstLoadingFilter.forceAllowTreeLoading(AstLoadingFilter.java:150)
at com.intellij.codeInsight.daemon.impl.InspectionRunner.lambda$processInOrderAsync$13(InspectionRunner.java:332)
at com.intellij.util.AstLoadingFilter.disallowTreeLoading(AstLoadingFilter.java:129)
at com.intellij.util.AstLoadingFilter.disallowTreeLoading(AstLoadingFilter.java:118)
at com.intellij.codeInsight.daemon.impl.InspectionRunner.lambda$processInOrderAsync$14(InspectionRunner.java:332)
at com.intellij.concurrency.JobLauncherImpl$2MyProcessQueueTask.lambda$call$0(JobLauncherImpl.java:460)
at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$executeProcessUnderProgress$12(CoreProgressManager.java:649)
at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:724)
at com.intellij.openapi.progress.impl.CoreProgressManager.computeUnderProgress(CoreProgressManager.java:680)
at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:648)
at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:78)
at com.intellij.concurrency.JobLauncherImpl$2MyProcessQueueTask.call(JobLauncherImpl.java:446)
at com.intellij.concurrency.JobLauncherImpl$2MyProcessQueueTask.call(JobLauncherImpl.java:431)
at com.intellij.concurrency.JobLauncherImpl$1.compute(JobLauncherImpl.java:416)
at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:754)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:686)
at com.intellij.codeInsight.daemon.impl.InspectionRunner.lambda$inspect$5(InspectionRunner.java:185)
at com.intellij.codeInspection.InspectionEngine.withSession(InspectionEngine.java:246)
at com.intellij.codeInsight.daemon.impl.InspectionRunner.inspect(InspectionRunner.java:114)
at com.intellij.codeInsight.daemon.impl.LocalInspectionsPass.collectInformationWithProgress(LocalInspectionsPass.java:142)
at com.intellij.codeInsight.daemon.impl.ProgressableTextEditorHighlightingPass.doCollectInformation(ProgressableTextEditorHighlightingPass.java:80)
at com.intellij.codeHighlighting.TextEditorHighlightingPass.collectInformation(TextEditorHighlightingPass.java:55)
at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.lambda$doRun$2(PassExecutorService.java:410)
at com.intellij.platform.diagnostic.telemetry.helpers.TraceKt.runWithSpanIgnoreThrows(trace.kt:85)
at com.intellij.platform.diagnostic.telemetry.helpers.TraceUtil.runWithSpanThrows(TraceUtil.java:34)
at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.lambda$doRun$3(PassExecutorService.java:405)
at com.intellij.openapi.application.impl.RwLockHolder.tryRunReadAction(RwLockHolder.kt:310)
at com.intellij.openapi.application.impl.ApplicationImpl.tryRunReadAction(ApplicationImpl.java:925)
at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.lambda$doRun$4(PassExecutorService.java:396)
at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$executeProcessUnderProgress$12(CoreProgressManager.java:649)
at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:724)
at com.intellij.openapi.progress.impl.CoreProgressManager.computeUnderProgress(CoreProgressManager.java:680)
at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:648)
at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:78)
at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.doRun(PassExecutorService.java:395)
at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.lambda$run$0(PassExecutorService.java:370)
at com.intellij.openapi.fileTypes.impl.FileTypeManagerImpl.cacheFileTypesInside(FileTypeManagerImpl.java:789)
at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.lambda$run$1(PassExecutorService.java:369)
at com.intellij.openapi.application.impl.ReadMostlyRWLock.executeByImpatientReader(ReadMostlyRWLock.java:199)
at com.intellij.openapi.application.impl.RwLockHolder.executeByImpatientReader(RwLockHolder.kt:478)
at com.intellij.openapi.application.impl.ApplicationImpl.executeByImpatientReader(ApplicationImpl.java:182)
at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.run(PassExecutorService.java:367)
at com.intellij.concurrency.JobLauncherImpl$VoidForkJoinTask$1.exec(JobLauncherImpl.java:188)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
The core code I used to build LightMethodBuilder is
public PsiMethod createMethod(Project project, String builderName, PsiManager psiManager, GlobalSearchScope resolveScope, PsiClass psiClass) {
PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
// builderNameForFactory is the method name
String builderNameForFactory = NameUtil.getNameForFactory(builderName);
// Get return type
PsiClass returnBuilderClass = JavaPsiFacade.getInstance(project).findClass(builderName, resolveScope);
if (returnBuilderClass == null) {
return null;
}
PsiClassType objectType = elementFactory.createTypeByFQClassName("java.lang.Object", resolveScope);
// Create type parameter T
PsiTypeParameter typeParameter = elementFactory.createTypeParameter("T", new PsiClassType[]{objectType});
PsiClassType genericBuilderType = elementFactory.createType(returnBuilderClass, new PsiType[]{elementFactory.createType(typeParameter)});
// Create the method using LightMethodBuilder
LightMethodBuilder methodBuilder = new LightMethodBuilder(psiManager, JavaLanguage.INSTANCE, builderNameForFactory)
.setMethodReturnType(genericBuilderType)
.addModifier(PsiModifier.PUBLIC)
.addModifier(PsiModifier.STATIC);
// Add the String chainId parameter
PsiType javaLangStringType = elementFactory.createTypeFromText("java.lang.String", null);
PsiParameter chainIdParameter = elementFactory.createParameter("chainId", javaLangStringType);
methodBuilder.addParameter(chainIdParameter);
// Build the ChainTypeReference<T> type
PsiClass chainTypeReferenceClass = Objects.requireNonNull(elementFactory.createTypeByFQClassName(ParamsClass.CHAIN_TYPE_REFERENCE.getClassName(), resolveScope).resolve());
// Create a ChainTypeReference type that contains the generic T
PsiClassType chainTypeReferenceTypeWithGeneric = elementFactory.createType(chainTypeReferenceClass, new PsiType[]{elementFactory.createType(typeParameter)});
// Add generic parameters to the method
PsiParameter chainTypeReferenceParameter = elementFactory.createParameter("chainTypeReference", chainTypeReferenceTypeWithGeneric);
methodBuilder.addTypeParameter(typeParameter);
methodBuilder.addParameter(chainTypeReferenceParameter);
methodBuilder.setNavigationElement(psiClass);
methodBuilder.setContainingClass(psiClass);
return methodBuilder;
}
What can I do to get my generics to infer correctly and solve the error problem
Please sign in to leave a comment.
Hi Ben,
I don't see what can be a problem in your code. Could you please try using
LighTypeParameterBuilder
like here?https://github.com/JetBrains/intellij-community/blob/master/java/java-tests/testSrc/com/intellij/java/psi/MiscPsiTest.java#L398-L403
Hi Karol,
I tried to fix it after reading the code sample
Finally, I found that the problem was that I seemed to misuse PsiParameter to generate the two parameters required for function signatures, such as String chainId, ChainTypeReference<T> chainTypeReference
When I bind chainTypeReference to generic T with the following code
I type the parameters after the call and the error described earlier occurs, like
java.lang.IllegalStateException: Parameter: PsiParameter:chainTypeReference; siblings: [PsiParameter:chainTypeReference]; ancestors: DummyHolder
But in the code you give, I find that generic parameters seem to be used like this
So I tried to modify my use of parameters and generics, and it worked
Although none of this is directly related to
LighTypeParameterBuilder
, the code example you gave me still inspired meI have posted my improved code here in the hope that it will be helpful to anyone who has encountered similar problems
Thank you so much for your help, Karol.