in reply to linting for undefined object methods

Do you mean making sure method exists given the code $x->method()?

How do you expect the linter to know all of the classes of which $x could be an instance and all of the namespaces whose name $x could contain.

I guess you could do an imperfect job if you knew some possible values for $x. That raises the following question:

How do you expect the linter to know any of the classes of which $x could be an instance or any of the namespaces whose name $x could contain.

Update: Now takes class methods into consideration.

Replies are listed 'Best First'.
Re^2: linting for undefined object methods
by aespen (Initiate) on Sep 01, 2009 at 21:32 UTC
    We are using a simple, restrictive OO methodology which should be fairly well lintable at compile time. All methods are known at compile time. We are not using perl's AUTOLOAD feature or any other sort of dynamic method generation. All objects are created with a call to CLASS->new() (no dynamic re-blessing) and the class hierarchy is contained in @ISA. I guess this is too much of a corner case for support in the general B::Lint module, but the bottom line is we miss catchable stuff at compile time that causes real problems. Maybe I should write a plugin for Lint for this sort of situation.

      By having the linter make the giant assumption that all subs are methods, that tells you a bit about $self, but not enough. It only helps determine that cases such as the following aren't problems:

      { package Base; sub x { ... } } { package Child; our @ISA = 'Base'; sub y { shift->x } }

      However, it doesn't help determine that something is a problem. For example, is there a problem in the following?

      package Package; sub y { shift->x }

      No, turns out package Package is just a role:

      { package SomeRole; # Implementor must provide y sub y { shift->x } } { package Class; our @ISA = 'SomeRole'; sub x { ... } }

      But that's not the real test. How often do you call a child method that doesn't exist? I expect the majority of problems to be in code such as the following:

      sub some_method { my ($self, $arg) = @_ ... $arg->other_method(); ... }
      or
      sub some_method { my ($self) = @_ ... $self->attribute->other_method(); ... }

      The linter knows absolutely nothing about the class or object whose method other_method is being called, so it has no idea if other_method exists for that class or object.

        This all makes sense to me, but given the constraint of statically defined methods, would it be reasonable to have the linter locate method names in known namespaces or else give warning? For method invocations on references where the class cannot be known at compile time, this would at least catch the 'method doesn't exist anywhere in a known namespace' type of error. I understand that this is not useful in the general case, but with 100K lines of code strewn over 200 files and classes with fairly verbose method names it sure would be nice to know that
        $dataView->htmTable('edit');
        will fail when the method is actually called
        sub htmlTable { }
        When $dataView's class cannot be known, having 'htmlTable' exist somewhere in the application namespace is clearly no guarantee of success at runtime... but missing the 'htmTable' bug is a *definite* guarantee that there will be a problem. A lint check, imperfect as it may be, still seems to offer value in my case.
      Thanks for explaining the "corner cases".

      Maybe I should write a plugin for Lint for this sort of situation.

      Maybe you should consider to have a look into PPI for static parsing and/or B::Xref and something like B::Concise for parsing after compilation.

      Cheers Rolf

      UPDATET distinction between static and compilation parsing