ContentBasedClassFileProcessor and File Structure navigation

I'm using ContentBasedClassFileProcessor to provide decompiled file source and this works as expected - source is shown.
Now for such editor I open File Structure popup (Navigate -> File Structure) and select some method - caret jumps to seemingly random place in file.

Is it possible to trigger some kind of refresh so that navigation works correctly ?

4 comments

No, it's not. The behavior you see is a bug in the platform, and unfortunately there's nothing you can do in the plugin as a workaround.
http://youtrack.jetbrains.com/issue/IDEA-100029

0

Yes that would be great to have it fixed. one day or another ;)

0

Hi,

I have been looking at the following extension point ClsFileDecompiledPsiFileProvider and that have been promising up to a certain point. It actually solved the wrong references in the decompiled file. But it doesn't solve it all.
For example clicking on a memeber of another class that need to be decompiled opens the file at the wrong location, also navigating to the declaration of an internal member or method variable doesn't work.

Here's how I build the PsiFile :

PsiFile fileFromDecompiledText = PsiFileFactory.getInstance(clsFile.getProject()).createFileFromText(         clsFile.getName(),         clsFile.getLanguage(),         decompiledText,          // my decompiled text         false,                   // physical         false                    // markAsCopy );


It all seem to be related to the mirror of some PsiElement. And some times it's the IntelliJ source that is used to build the mirror. I haven't fully investigated how or why the getMirror can still use the IntelliJ source, but seems there is many way for that. For example opening the definition of a class in a popup (Cmd+Shift+I), navigating in the fie, outside the file, maybe reference hightlighting, etc.



I have tried the ClsCustomNavigationPolicy extension as well, but that didn't work as expected, I'm probably missing things here.
And still the navigation policy, doesn't seem to apply to internal members, or local variables.

Here's what I tried :

@Nullable @Override public PsiElement getNavigationElement(@NotNull ClsClassImpl clsClass) {
    PsiClass sourceClassMirror = findSourceClassMirror(clsMethod);     if (sourceClassMirror == null) return null; // not found     for (PsiMethod sourceMethod : sourceClassMirror.findMethodsByName(clsMethod.getName(), false)) {         if (MethodSignatureUtil.areParametersErasureEqual(clsMethod, sourceMethod)) {             return sourceMethod.getNavigationElement();  // <= this is not working unfortunately, IDEA doesn't go to this element         }     }     return null;
}

@Nullable
// note: in later version IntelliJ introduced a ClsMemberImpl, this is ok here as it is only called for method and fields inside this extension public PsiClass findSourceClassMirror(@NotNull ClsElementImpl clsMember) {

    // simple scenario to get the PsiFile from my decompiler.     ClsClassImpl memberOwner = (ClsClassImpl) clsMember.getParent();     PsiFile decompiledPsiFile = javaClassDecompiledPsiFileProvider.getDecompiledPsiFile((PsiJavaFile) memberOwner.getParent());     PsiElement navigationElement = decompiledPsiFile.getNavigationElement();     PsiClassOwner fileNavigationElement = (PsiClassOwner) navigationElement.getNavigationElement();     for (PsiClass aClass : fileNavigationElement.getClasses()) {         if (memberOwner.getName().equals(aClass.getName())) return aClass;     }     return null; // not found }



At the moment I'm a bit puzzled as how to get around that or if that's possible without reimplementing a whole world of Java for compiled classes.

Cheers,
Brice

0

Please sign in to leave a comment.