castwide / solargraph

A Ruby language server.
https://solargraph.org
MIT License
1.87k stars 154 forks source link

Autocompletion broken : Infinite loop when checking if a class is a superclass #641

Closed QuentinLemCode closed 1 year ago

QuentinLemCode commented 1 year ago

Hello Currently working on a rails project with engines There is this actual folder structure

app
--controllers
----application_controller.rb
----admin
------application_controller.rb
--helpers
----admin
------resque_helpers.rb
engines
--platform
----app
------admin
--------application_controller.rb

So here is the class declaration of app/controllers/application_controller.rb

class Admin::ApplicationController < ApplicationController

And here is the class declaration of engines/platform/app/admin/application_controller.rb

class Platform::Admin::ApplicationController < Admin::ApplicationController

So, when working on controller of this engine, trying to call autocompletion on ResqueHelpers broke completely solargraph as it doesn't respond anymore after the first autocomplete call.

I added a bunch of logging to find the issue. I found out it come from super_and_sub? method from ApiMap class. https://github.com/castwide/solargraph/blob/master/lib/solargraph/api_map.rb#LC460

    def super_and_sub?(sup, sub)
      fqsup = qualify(sup)
      cls = qualify(sub)
      until fqsup.nil? || cls.nil?
        return true if cls == fqsup
        cls = qualify_superclass(cls)
      end
      false
    end

Here is the logging I got :

[WARN] method super_and_sub? called with 'Admin::ResqueHelpers','Platform::Admin::AnotherController'
[WARN] method qualify called with 'Admin::ResqueHelpers',''
[WARN] qualify return cached 'Admin::ResqueHelpers'
[WARN] fqsup : 'Admin::ResqueHelpers'
[WARN] method qualify called with 'Platform::Admin::AnotherController',''
[WARN] qualify return cached 'Platform::Admin::AnotherController'
[WARN] cls : 'Platform::Admin::AnotherController'
[WARN] method qualify called with 'Platform::Admin::ApplicationController','Platform::Admin'
[WARN] qualify return cached 'Platform::Admin::ApplicationController'
[WARN] method qualify called with  'Admin::ApplicationController','Platform::Admin'
[WARN] qualify return cached 'Platform::Admin::ApplicationController'
[WARN] method qualify called with  'Admin::ApplicationController','Platform::Admin'
[WARN] qualify return cached 'Platform::Admin::ApplicationController'
[WARN] method qualify called with  'Admin::ApplicationController','Platform::Admin'
[WARN] qualify return cached 'Platform::Admin::ApplicationController'
... etc infinitely

For now, I have added a limit of 100 on the until.

Can you fix this issue please ? At least add a limit to prevent infinite loops.

castwide commented 1 year ago

Version 0.49.0 includes a change that drops out of super_and_sub? when it encounters a previously tested class. I suspect I need to investigate a lower level root cause for superclasses having circular references, but this should at least avoid infinite loops.

If the problem persists, please let me know.

QuentinLemCode commented 1 year ago

Great, will try it asap

QuentinLemCode commented 1 year ago

Issue fixed ! Thanks