Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Null checks & Issue with resolution of "Unknown.hx" #936

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from

Conversation

WolfieWerewolf
Copy link

Eric,
I thought I would be helpful for a change. Please see the commit notes.

… in particular, in HaxePackageModel starting at line 125 the getFile(String fileName){} method was throwing when attempting to resolve "Unknown.hx". This fix is a hack. Where could this request be coming from? To reproduce in the code without this filter, add two macro definitions to the Haxe plugin (js, cpp). Create a haxe class and annotate as follows:

#if js
typedef ArrayBuffer = js.lib.ArrayBuffer;
#else

then change it as follows
#if js
typedef ArrayBuffer = js.lib.ArrayBuffer;
#end
#if cpp
....
#end
@EricBishton EricBishton changed the base branch from master to develop July 10, 2019 02:03
//System.out.println("-----------------------------------");
//System.out.println(fileName + ".hx");
//System.out.println("-----------------------------------");
System.out.println(Arrays.toString(e.getStackTrace()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always use the HaxeDebugLogger instead of any of the System io dumps (out, err); the System calls can create write dead-locks when multiple JetBrains products are used simultaneously or when called on background threads (for example, see #724). They are also not captured in user logs where they could be useful for debugging.

HaxeDebugLogger.getLogger().warn("Message"); is the easy way to add a temporary message. There are many examples of more interesting usage throughout the code base.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool..thanks for that tip.

PsiFile file;
try {
String fName = fileName + ".hx";
//TODO @ Eric. What could be the source of a request for "Unknown.hx" ?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a magic type of "unknown" in the language that is assigned to variables before type inference is able to set the type. (It's the same in the compiler -- just trace(some_uninitialized_var); to see it pop out.) If the resolver gets a variable in this condition, it's going to try and find the class by upper-casing the name and looking for an implementation file. Were we throwing an exception out of this function? What was the bug that made you look here?

(BTW, ProcessCanceledExceptions are expected and should cancel the current task. That's the way that IntelliJ deals with blocked/blocking tasks.)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah whenever it tried to load "Unknown.hx" it was throwing. The Intellij stack trace got me there eventually.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I just noticed your BTW. That may be true but when it threw here it stopped parsing code. This is evident if you can repro from my instructions in the commit notes.

Copy link
Member

@EricBishton EricBishton Jul 10, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been unable to repro the exception being thrown and parsing stopping. If I set a breakpoint in getFile(), I can definitely see the code trying to find the file -- every time an unknown class reference is created. Issue #938 is for that.

try {
String fName = fileName + ".hx";
//TODO @ Eric. What could be the source of a request for "Unknown.hx" ?
if(fName.equals("Unknown.hx")){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, there is nothing in the language that says you can't have a class called Unknown and an Unknown.hx file to go with it. So, just returning null when we see that name is going to create other bugs.

Perhaps we should rename our internal unknown class to __unknown__? The double leading underscore is soft-reserved for compiler internals anyway. Unfortunately, I'm sure that it will pop out to the UI somewhere...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree...I didnt expect my little hack to be permanent.. Shall I try to find that magic type and rename it as you recommended?

@EricBishton
Copy link
Member

I changed the merge base to "develop", which is really the current development line. "master" is being updated only upon release at the moment. I might change that, but that's the current M.O..

@EricBishton
Copy link
Member

I should have said this right at the beginning: Thank You!! for helping out. It's great to have another pair of hands working on the code.

@WolfieWerewolf
Copy link
Author

My pleasure. It will take me some time to get up to speed with your substantial code base but I'm invested in this both personally and professionally. Thanks for all your help too.

@WolfieWerewolf
Copy link
Author

So do I understand correctly that to resolve this code review my actions are:

  1. Replace any System.out.println's with your approach (even the commented ones)
  2. Attempt to find the magic Unknown type and rename all references to it
    Is there another action for me?

@mayakwd
Copy link
Contributor

mayakwd commented Jul 10, 2019

I don't understand an approach inside HaxePackageModel#getFile, could you please explain your code.
Also I don't see any reason to rename any references of Unknown-type.

@WolfieWerewolf
Copy link
Author

Hi @mayakwd . Certainly. When parsing this code
https://github.com/WolfieWerewolf/snow/blob/master/snow/api/buffers/Int16Array.hx
I changed the

#else 

on line 51 to

#end
#if cpp

using the latest Haxe plugin from the development branch. I had previously defined macro's in the haxe plugin for both "js" and "cpp" The plugin started to parse the green comment style code in the #else block and then threw an error and stopped. So I checked the stack trace and eventually I eneded up in HaxePackageModel.hx where I discovered that somewhere along the line a request is made to load "Unknown.hx" which does not exist in this project and whenever that request is made it bails. My approach above was to demonstrate the idea and ask for further information, it wasn't intended to be a final solution. Please see if you can reproduce my findings. When I added that crude filter it stopped throwing and completed parsing the code in question. My question is, why is the plugin trying to load "Unknown.hx" when no such file exists?

@EricBishton
Copy link
Member

Hi Wolfie, I missed the notes in the change itself. :/ I need to pay more attention to those...

At any rate: Your changes for HaxeResolver.java are good. The changes to HaxeReferenceImpl don't involve any logic change so are also fine. If you submit those as a separate PR, I will merge it.

The change to HaxePackageModel, while it stops the problem from occurring, is not the root of the issue. We need to look at the code calling getFile() and figure out why it doesn't understand that the internal type doesn't really exist. It's created in SpecificTypeReference.getUnknown(). We can change the constant string easily enough (SpecificTypeReference.UNKNKOWN).

In fact, I just discovered a bug in SpecificTypeReference.isUnknown() that checks whether a reference is the internal type by using the type name, and it will give an incorrect result if somebody actually creates a type named Unknown.

Also, I'd like to know why looking up a file name is causing parsing to stop, if it's because of anything other than a ProcessCanceledException. If it is consistently stopped by a PCE, we should investigate putting the process on a background thread and/or breaking the process up into smaller chunks that don't overshoot the thread timeouts. Also, there may be an issue with using the virtual file system to find a non-existent file.

Finally, I'd like to figure out if the cancellation is causing a bug in the conditional block processing or if it's in the parser itself. (They do interact at parsing time.)

@EricBishton
Copy link
Member

I've filed bugs #937 and #938 to track the issues with "Unknown".

@WolfieWerewolf
Copy link
Author

WolfieWerewolf commented Jul 10, 2019 via email

@EricBishton
Copy link
Member

Have you tried it with the snow project that I mentioned?

I have tried it with the content of the file, but not in situ. How did you know that parsing stopped? Was there an error marking or something?

@WolfieWerewolf
Copy link
Author

WolfieWerewolf commented Jul 10, 2019 via email

@EricBishton
Copy link
Member

So, I was able to repro in situ. When in the middle of typing, I was getting NPEs., and then after the typing was finished, I had the badly colored text for a bit. I opened "Tools->View PSI of current file" which caused a re-parse and didn't show the error. When I closed the PSI viewer, the file had been reparsed and not showing an error.

The NPE report (from idea.log):
2019-07-10 12:18:41,651 [50711504] ERROR - aemon.impl.PassExecutorService - IntelliJ IDEA 2018.3.6 Build #IU-183.6156.11
2019-07-10 12:18:41,651 [50711504] ERROR - aemon.impl.PassExecutorService - JDK: 1.8.0_152-release; VM: OpenJDK 64-Bit Server VM; Vendor: JetBrains s.r.o
2019-07-10 12:18:41,651 [50711504] ERROR - aemon.impl.PassExecutorService - OS: Windows 10
2019-07-10 12:18:41,651 [50711504] ERROR - aemon.impl.PassExecutorService - Last Action: EditorLineStart
2019-07-10 12:18:42,422 [50712275] ERROR - aemon.impl.PassExecutorService - null
java.lang.NullPointerException
at com.intellij.plugins.haxe.lang.psi.HaxeResolver.resolveByClassAndSymbol(HaxeResolver.java:433)
at com.intellij.plugins.haxe.lang.psi.HaxeResolver.doResolve(HaxeResolver.java:122)
at com.intellij.psi.impl.source.resolve.ResolveCache.lambda$resolve$0(ResolveCache.java:150)
at com.intellij.openapi.util.RecursionManager$2.doPreventingRecursion(RecursionManager.java:98)
at com.intellij.psi.impl.source.resolve.ResolveCache.resolve(ResolveCache.java:149)
at com.intellij.psi.impl.source.resolve.ResolveCache.resolveWithCaching(ResolveCache.java:239)
at com.intellij.plugins.haxe.lang.psi.HaxeResolver.resolve(HaxeResolver.java:77)
at com.intellij.plugins.haxe.lang.psi.impl.HaxeReferenceImpl.multiResolve(HaxeReferenceImpl.java:215)
at com.intellij.plugins.haxe.lang.psi.impl.HaxeReferenceImpl.multiResolve(HaxeReferenceImpl.java:254)
at com.intellij.plugins.haxe.lang.psi.impl.HaxeReferenceImpl.resolve(HaxeReferenceImpl.java:268)
at com.intellij.plugins.haxe.lang.psi.impl.HaxeReferenceImpl.resolve(HaxeReferenceImpl.java:167)
at com.intellij.plugins.haxe.ide.annotator.HaxeAnnotatingVisitor.visitCallExpression(HaxeAnnotatingVisitor.java:86)
at com.intellij.plugins.haxe.lang.psi.impl.HaxeCallExpressionImpl.accept(HaxeCallExpressionImpl.java:20)
at com.intellij.psi.impl.PsiElementBase.acceptChildren(PsiElementBase.java:69)
at com.intellij.plugins.haxe.ide.annotator.HaxeAnnotatingVisitor.visitElement(HaxeAnnotatingVisitor.java:117)
at com.intellij.plugins.haxe.lang.psi.HaxeVisitor.visitPsiCompositeElement(HaxeVisitor.java:720)
at com.intellij.plugins.haxe.lang.psi.HaxeVisitor.visitExpression(HaxeVisitor.java:171)
at com.intellij.plugins.haxe.lang.psi.HaxeVisitor.visitAssignExpression(HaxeVisitor.java:56)
at com.intellij.plugins.haxe.lang.psi.impl.HaxeAssignExpressionImpl.accept(HaxeAssignExpressionImpl.java:20)
at com.intellij.psi.impl.PsiElementBase.acceptChildren(PsiElementBase.java:69)
at com.intellij.plugins.haxe.ide.annotator.HaxeAnnotatingVisitor.visitElement(HaxeAnnotatingVisitor.java:117)
at com.intellij.plugins.haxe.lang.psi.HaxeVisitor.visitPsiCompositeElement(HaxeVisitor.java:720)
at com.intellij.plugins.haxe.lang.psi.HaxeVisitor.visitBlockStatementPsiMixin(HaxeVisitor.java:636)
at com.intellij.plugins.haxe.lang.psi.HaxeVisitor.visitBlockStatement(HaxeVisitor.java:84)
at com.intellij.plugins.haxe.lang.psi.impl.HaxeBlockStatementImpl.accept(HaxeBlockStatementImpl.java:20)
at com.intellij.psi.impl.PsiElementBase.acceptChildren(PsiElementBase.java:69)
at com.intellij.plugins.haxe.ide.annotator.HaxeAnnotatingVisitor.visitElement(HaxeAnnotatingVisitor.java:117)
at com.intellij.plugins.haxe.lang.psi.HaxeVisitor.visitPsiCompositeElement(HaxeVisitor.java:720)
at com.intellij.plugins.haxe.lang.psi.HaxeVisitor.visitMethod(HaxeVisitor.java:664)
at com.intellij.plugins.haxe.ide.annotator.HaxeAnnotatingVisitor.visitMethodDeclaration(HaxeAnnotatingVisitor.java:78)
at com.intellij.plugins.haxe.lang.psi.impl.HaxeMethodDeclarationImpl.accept(HaxeMethodDeclarationImpl.java:20)
at com.intellij.psi.impl.PsiElementBase.acceptChildren(PsiElementBase.java:69)
at com.intellij.plugins.haxe.ide.annotator.HaxeAnnotatingVisitor.visitElement(HaxeAnnotatingVisitor.java:117)
at com.intellij.plugins.haxe.lang.psi.HaxeVisitor.visitPsiCompositeElement(HaxeVisitor.java:720)
at com.intellij.plugins.haxe.lang.psi.HaxeVisitor.visitClassBody(HaxeVisitor.java:110)
at com.intellij.plugins.haxe.lang.psi.HaxeVisitor.visitAbstractBody(HaxeVisitor.java:10)
at com.intellij.plugins.haxe.lang.psi.impl.HaxeAbstractBodyImpl.accept(HaxeAbstractBodyImpl.java:20)
at com.intellij.psi.impl.PsiElementBase.acceptChildren(PsiElementBase.java:69)
at com.intellij.plugins.haxe.ide.annotator.HaxeAnnotatingVisitor.visitElement(HaxeAnnotatingVisitor.java:117)
at com.intellij.plugins.haxe.lang.psi.HaxeVisitor.visitPsiCompositeElement(HaxeVisitor.java:720)
at com.intellij.plugins.haxe.lang.psi.HaxeVisitor.visitClass(HaxeVisitor.java:640)
at com.intellij.plugins.haxe.lang.psi.HaxeVisitor.visitAbstractClassDeclaration(HaxeVisitor.java:14)
at com.intellij.plugins.haxe.lang.psi.impl.HaxeAbstractClassDeclarationImpl.accept(HaxeAbstractClassDeclarationImpl.java:20)
at com.intellij.psi.impl.source.tree.SharedImplUtil.acceptChildren(SharedImplUtil.java:200)
at com.intellij.psi.impl.source.PsiFileImpl.acceptChildren(PsiFileImpl.java:730)
at com.intellij.plugins.haxe.ide.annotator.HaxeAnnotatingVisitor.visitElement(HaxeAnnotatingVisitor.java:117)
at com.intellij.psi.PsiElementVisitor.visitFile(PsiElementVisitor.java:34)
at com.intellij.plugins.haxe.ide.inspections.HaxeUnresolvedSymbolInspection.checkFile(HaxeUnresolvedSymbolInspection.java:84)
at com.intellij.codeInspection.LocalInspectionTool$1.visitFile(LocalInspectionTool.java:141)
at com.intellij.extapi.psi.PsiFileBase.accept(PsiFileBase.java:70)
at com.intellij.codeInspection.InspectionEngine.acceptElements(InspectionEngine.java:75)
at com.intellij.codeInsight.daemon.impl.LocalInspectionsPass.lambda$null$7(LocalInspectionsPass.java:316)
at com.intellij.util.AstLoadingFilter.lambda$toComputable$2(AstLoadingFilter.java:168)
at com.intellij.util.AstLoadingFilter.disallowTreeLoading(AstLoadingFilter.java:126)
at com.intellij.util.AstLoadingFilter.disallowTreeLoading(AstLoadingFilter.java:115)
at com.intellij.util.AstLoadingFilter.disallowTreeLoading(AstLoadingFilter.java:110)
at com.intellij.codeInsight.daemon.impl.LocalInspectionsPass.lambda$visitRestElementsAndCleanup$8(LocalInspectionsPass.java:315)
at com.intellij.concurrency.ApplierCompleter.execAndForkSubTasks(ApplierCompleter.java:133)
at com.intellij.openapi.application.impl.ApplicationImpl.tryRunReadAction(ApplicationImpl.java:1168)
at com.intellij.concurrency.ApplierCompleter.lambda$wrapInReadActionAndIndicator$1(ApplierCompleter.java:105)
at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:582)
at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:532)
at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:87)
at com.intellij.concurrency.ApplierCompleter.wrapInReadActionAndIndicator(ApplierCompleter.java:116)
at com.intellij.concurrency.ApplierCompleter.lambda$compute$0(ApplierCompleter.java:96)
at com.intellij.openapi.application.impl.ReadMostlyRWLock.executeByImpatientReader(ReadMostlyRWLock.java:147)
at com.intellij.openapi.application.impl.ApplicationImpl.executeByImpatientReader(ApplicationImpl.java:222)
at com.intellij.concurrency.ApplierCompleter.compute(ApplierCompleter.java:96)
at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

@WolfieWerewolf
Copy link
Author

WolfieWerewolf commented Jul 10, 2019 via email

@EricBishton
Copy link
Member

Here's a patch to replace HaxeResolver.java: line 433:
Replace

          final HaxeClass underlyingClass = model.getUnderlyingClass(reference.getSpecialization().toGenericResolver(leftClass));

with

          HaxeGenericSpecialization specialization = reference.getSpecialization();
          HaxeGenericResolver resolver = specialization != null ? specialization.toGenericResolver(leftClass) : null;
          final HaxeClass underlyingClass = model.getUnderlyingClass(resolver);

This fixes the crash that I saw above when I'm running in a heavily modified dev branch. I can't get the NPE to repro using the same project, but a clean dev tree.

Since I can't verify that this changes anything on a clean tree, I'm giving up for now.

EricBishton added a commit to EricBishton/intellij-haxe that referenced this pull request Aug 3, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants