LightCodeInsightFixtureTestCase unable to resolve PsiReferenceExpression
Hello,
I am implementing a plugin, where I am resolving a PsiReferenceExpression related to PsiMethodCallExpression. When I execute the plugin, I get the result back with appropriate element.
fun isCipherMethodCall(expression: PsiMethodCallExpression): Boolean {
val el = expression.methodExpression.resolve()
if (el != null) {
val classElement = el.getContainingClass()
if (classElement != null && classElement.name.equals("Cipher"))
return true
}
return false
}
I am currently writing a test to evaluate a feature which makes use of the above method. I am writing tests using by extending a LightCodeInsightFixtureTestCase.
When I execute the test, it returns null for the value of el.
After debugging I found out that expression.methodExpression returns the PsiReferenceExpression and on resolve it is getting the null value in return.
When plugin runs, it gets the appropriate element from MethodCandidateInfo class.
When test runs, getElement() of JavaResolveResult interface gets executed which returns null. JavaResolveResult extends ResolveResult.
public interface JavaResolveResult extends ResolveResult {
JavaResolveResult[] EMPTY_ARRAY = new JavaResolveResult[0];
JavaResolveResult EMPTY = new JavaResolveResult() {
public PsiElement getElement() {
return null;
}
How to resolve the element and this issue, so that test runs correctly and evaluates the element.
请先登录再写评论。
In your test, do you add the appropriate JDK/libraries to the test module dependencies? Does "JavaPsiFacade#findClass(className, allScope)" find the "Cipher" class by its qualified name?
Any hints will be appreciated :)
Hi,
I guess that you need to setup a corresponding library or mock required classes with methods via `myFixture.addClass()`. If it doesn't help, please attach your test as most probably there is an issue with setup.
Thanks,
Anna
Hey Anna and Peter,
My test setup looks like:
1. I have added class using `myFixture.addClass()`.
2. Tested using "JavaPsiFacade#findClass(className, allScope)" and found PsiClass:Cipher.
Test is still evaluating the same way as described.
3. Adding the jar (seems like `jce.jar` is having javax.crypto) using `PsiTestUtil#addLibrary()` gives com.intellij.openapi.util.TraceableDisposable$DisposalException: Virtual pointer hasn't been disposed.
This exception occurs after the completion of test.
Please ensure that your test file text has all the necessary imports, and the created file is under some source root (FileIndexFacade#isInSourceContent). If that doesn't help, I'd suggest to debug the resolve. I'd put a breakpoint into com.intellij.psi.impl.source.PsiJavaFileBaseImpl#processDeclarationsNoGuess and see if imports are processed as you expect.
Thanks for the direction.
I have debugged the com.intellij.psi.impl.source.PsiJavaFileBaseImpl#processDeclarationsNoGuess and found out that import statement which is related to Cipher class gets correctly resolved with PsiClass:Cipher element.
But after resolving the element to PsiClass, the getContainingClass() returns null on the element.
I guess that `Cipher` is not a nested class (it's located in Cipher.java as stated above) and thus it's expected that it has no containing class.
That's true. So PsiClass is getting resolved, but not being passed to the original call. I will try to trace it again and see where I am missing the link.
I ran a small experiment by resolving methodCall java.lang.String#split. TestCase has java.lang imported.
1. Plugin is able to resolve it correctly.
2. LightCodeInsightFixturetestCase unable to resolve the same methodCall.
3. As per documentation, LightCodeInsightFixturetestCase should be used for tests that require the Java PSI or any related functionality. Does that mean LightCodeInsightFixturetestCase adds required dependencies:?
4. After adding class java.lang.String using myFixture#addClass, test is resolving the methodCall correctly.
5. I have marked the testData directory as Test Resources Root. Will this effect the end result? I have marked it as Test Resources Root because I don't want the code in testData to be compile every time I build the Plugin or run the tests.
Classes from jdk should be resolved, cause mock jdk is added automatically to the dependencies based on project descriptor of the test. The light tests (e.g. LightCodeInsightFixturetestCase) should not add any libraries or change the jdk during setup so the only possibility to enforce resolve to external classes is to add them as #addClass. If the test data is found, it doesn't mean how your project is configured, the project created during test run won't be affected in any way.
So you still have the class resolved though references on methods from the class are not resolved?
Yes, I am still facing the issue of resolving methodCallExpressions.
1. I am only overriding getTestDataPath()
2. I am using following VM options in runConfiguration:
3. I am adding Cipher class using myFixture#addClass()
Why do you need junit 5 plugin in your tests? Anyway, you need to pass required plugin ids in one property, comma (",") separated. And most important, you need to add your plugin explicitly here, otherwise it would be skipped as are skipped all other plugins.
-Didea.test.group has no influence on local tests and is used in our shared configurations for CI integration. idea.home.path/system/config should be written automatically by devkit plugin, you don't need to specify it explicitly.