Commit 0dc7335e authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Check circular dependencies before resolving @inheritdoc.

Otherwise the documentation inheriting process will run into infinite
loop.

For example the following code cause a problem:

    /**
     * @class
     * @extends B
     */
    A = {};

    /**
     * @class
     * @extends A
     */
    B = {c: 'd'};

That's fixed now.
parent 9b951f07
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ require 'jsduck/inherit_doc'
require 'jsduck/importer'
require 'jsduck/return_values'
require 'jsduck/lint'
require 'jsduck/circular_deps'

module JsDuck

@@ -95,6 +96,7 @@ module JsDuck

    # Do all kinds of post-processing on relations.
    def apply_extra_processing
      CircularDeps.new(@relations).check_all
      InheritDoc.new(@relations).resolve_all
      Importer.import(@opts.imports, @relations, @opts.new_since)
      ReturnValues.auto_detect(@relations)
+17 −0
Original line number Diff line number Diff line
require 'jsduck/logger'

module JsDuck

  # Checks for circular dependencies
  class CircularDeps
    def initialize(classes)
      @classes = classes
    end

    # Checks all classes for circular dependencies.
    #
    # When found, exits with a fatal error message.
    def check_all
      @classes.each do |cls|
        if chain = check(cls)
          Logger.fatal("Class #{cls[:name]} has a circular dependency: #{chain}")
          exit 1
        end
      end
    end

    # Checks class for circular dependencies.
    #
+0 −13
Original line number Diff line number Diff line
require 'jsduck/logger'
require 'jsduck/class'
require 'jsduck/circular_deps'

module JsDuck

@@ -21,7 +20,6 @@ module JsDuck
      warn_duplicate_members
      warn_singleton_statics
      warn_empty_enums
      fail_on_circular_dependencies
    end

    # print warning for each member or parameter with no name
@@ -119,17 +117,6 @@ module JsDuck
      end
    end

    # Print fatal error message for circular dependency.
    def fail_on_circular_dependencies
      circular_deps = CircularDeps.new
      @relations.each do |cls|
        if chain = circular_deps.check(cls)
          Logger.fatal("Class #{cls[:name]} has a circular dependency: #{chain}")
          exit 1
        end
      end
    end

    # Loops through all members of all classes
    def each_member(&block)
      @relations.each {|cls| cls.all_local_members.each(&block) }