@@ -13,6 +13,7 @@ class ApiMap
1313 autoload :SourceToYard , 'solargraph/api_map/source_to_yard'
1414 autoload :Store , 'solargraph/api_map/store'
1515 autoload :Index , 'solargraph/api_map/index'
16+ autoload :Constants , 'solargraph/api_map/constants'
1617
1718 # @return [Array<String>]
1819 attr_reader :unresolved_requires
@@ -261,19 +262,13 @@ def namespace_exists? name, context = ''
261262 # @return [Array<Solargraph::Pin::Base>]
262263 def get_constants namespace , *contexts
263264 namespace ||= ''
264- contexts . push '' if contexts . empty?
265- cached = cache . get_constants ( namespace , contexts )
266- return cached . clone unless cached . nil?
267- skip = Set . new
268- result = [ ]
269- contexts . each do |context |
270- fqns = qualify ( namespace , context )
271- visibility = [ :public ]
272- visibility . push :private if fqns == context
273- result . concat inner_get_constants ( fqns , visibility , skip )
274- end
275- cache . set_constants ( namespace , contexts , result )
276- result
265+ gates = contexts . clone
266+ gates . push '' if contexts . empty? && namespace . empty?
267+ gates . push namespace unless namespace . empty?
268+ store . constants
269+ . collect ( gates )
270+ . select { |pin | namespace . empty? || contexts . empty? || pin . namespace == namespace }
271+ . select { |pin | pin . visibility == :public || pin . namespace == namespace }
277272 end
278273
279274 # @param namespace [String]
@@ -299,44 +294,15 @@ def get_namespace_pins namespace, context
299294 # Should not be prefixed with '::'.
300295 # @return [String, nil] fully qualified tag
301296 def qualify tag , context_tag = ''
302- return tag if [ 'Boolean' , 'self' , nil ] . include? ( tag )
303-
304- context_type = ComplexType . try_parse ( context_tag ) . force_rooted
305- return unless context_type
306-
307- type = ComplexType . try_parse ( tag )
308- return unless type
309- return tag if type . literal?
310-
311- context_type = ComplexType . try_parse ( context_tag )
312- return unless context_type
313-
314- fqns = qualify_namespace ( type . rooted_namespace , context_type . rooted_namespace )
315- return unless fqns
316-
317- fqns + type . substring
297+ store . constants . qualify ( tag , context_tag )
318298 end
319299
320- # Determine fully qualified namespace for a given namespace used
321- # inside the definition of another tag ("context"). This method
322- # will start the search in the specified context until it finds a
323- # match for the namespace.
300+ # Get a fully qualified namespace from a reference pin.
324301 #
325- # @param namespace [String, nil] The namespace to
326- # match
327- # @param context_namespace [String] The context namespace in which the
328- # tag was referenced; start from here to resolve the name
329- # @return [String, nil] fully qualified namespace
330- def qualify_namespace ( namespace , context_namespace = '' )
331- cached = cache . get_qualified_namespace ( namespace , context_namespace )
332- return cached . clone unless cached . nil?
333- result = if namespace . start_with? ( '::' )
334- inner_qualify ( namespace [ 2 ..-1 ] , '' , Set . new )
335- else
336- inner_qualify ( namespace , context_namespace , Set . new )
337- end
338- cache . set_qualified_namespace ( namespace , context_namespace , result )
339- result
302+ # @param pin [Pin::Reference]
303+ # @return [String, nil]
304+ def dereference ( pin )
305+ store . constants . dereference ( pin )
340306 end
341307
342308 # @param fqns [String]
@@ -361,11 +327,10 @@ def get_instance_variable_pins(namespace, scope = :instance)
361327 result = [ ]
362328 used = [ namespace ]
363329 result . concat store . get_instance_variables ( namespace , scope )
364- sc = qualify_lower ( store . get_superclass ( namespace ) , namespace )
365- until sc . nil? || used . include? ( sc )
366- used . push sc
367- result . concat store . get_instance_variables ( sc , scope )
368- sc = qualify_lower ( store . get_superclass ( sc ) , sc )
330+ sc_fqns = namespace
331+ while ( sc = store . get_superclass ( sc_fqns ) )
332+ sc_fqns = store . constants . dereference ( sc )
333+ result . concat store . get_instance_variables ( sc_fqns , scope )
369334 end
370335 result
371336 end
@@ -660,13 +625,22 @@ def bundled? filename
660625 # @param sub [String] The subclass
661626 # @return [Boolean]
662627 def super_and_sub? ( sup , sub )
663- fqsup = qualify ( sup )
664- cls = qualify ( sub )
665- tested = [ ]
666- until fqsup . nil? || cls . nil? || tested . include? ( cls )
667- return true if cls == fqsup
668- tested . push cls
669- cls = qualify_superclass ( cls )
628+ sup = ComplexType . try_parse ( sup )
629+ sub = ComplexType . try_parse ( sub )
630+ # @todo If two literals are different values of the same type, it would
631+ # make more sense for super_and_sub? to return true, but there are a
632+ # few callers that currently expect this to be false.
633+ return false if sup . literal? && sub . literal? && sup . to_s != sub . to_s
634+ sup = sup . simplify_literals . to_s
635+ sub = sub . simplify_literals . to_s
636+ return true if sup == sub
637+ sc_fqns = sub
638+ while ( sc = store . get_superclass ( sc_fqns ) )
639+ sc_new = store . constants . dereference ( sc )
640+ # Cyclical inheritance is invalid
641+ return false if sc_new == sc_fqns
642+ sc_fqns = sc_new
643+ return true if sc_fqns == sup
670644 end
671645 false
672646 end
@@ -679,7 +653,7 @@ def super_and_sub?(sup, sub)
679653 #
680654 # @return [Boolean]
681655 def type_include? ( host_ns , module_ns )
682- store . get_includes ( host_ns ) . map { |inc_tag | ComplexType . parse ( inc_tag ) . name } . include? ( module_ns )
656+ store . get_includes ( host_ns ) . map { |inc_tag | inc_tag . parametrized_tag . name } . include? ( module_ns )
683657 end
684658
685659 # @param pins [Enumerable<Pin::Base>]
@@ -773,7 +747,7 @@ def inner_get_methods rooted_tag, scope, visibility, deep, skip, no_core = false
773747
774748 if deep && scope == :instance
775749 store . get_prepends ( fqns ) . reverse . each do |im |
776- fqim = qualify ( im , fqns )
750+ fqim = store . constants . dereference ( im )
777751 result . concat inner_get_methods ( fqim , scope , visibility , deep , skip , true ) unless fqim . nil?
778752 end
779753 end
@@ -787,7 +761,7 @@ def inner_get_methods rooted_tag, scope, visibility, deep, skip, no_core = false
787761 result . concat convention_methods_by_reference
788762
789763 if scope == :instance
790- store . get_include_pins ( fqns ) . reverse . each do |ref |
764+ store . get_includes ( fqns ) . reverse . each do |ref |
791765 const = get_constants ( '' , *ref . closure . gates ) . find { |pin | pin . path . end_with? ref . name }
792766 if const . is_a? ( Pin ::Namespace )
793767 result . concat inner_get_methods ( const . path , scope , visibility , deep , skip , true )
@@ -807,7 +781,7 @@ def inner_get_methods rooted_tag, scope, visibility, deep, skip, no_core = false
807781 else
808782 logger . info { "ApiMap#inner_get_methods(#{ fqns } , #{ scope } , #{ visibility } , #{ deep } , #{ skip } ) - looking for get_extends() from #{ fqns } " }
809783 store . get_extends ( fqns ) . reverse . each do |em |
810- fqem = qualify ( em , fqns )
784+ fqem = store . constants . dereference ( em )
811785 result . concat inner_get_methods ( fqem , :instance , visibility , deep , skip , true ) unless fqem . nil?
812786 end
813787 rooted_sc_tag = qualify_superclass ( rooted_tag )
@@ -828,95 +802,15 @@ def inner_get_methods rooted_tag, scope, visibility, deep, skip, no_core = false
828802 result
829803 end
830804
831- # @param fqns [String]
832- # @param visibility [Array<Symbol>]
833- # @param skip [Set<String>]
834- # @return [Array<Pin::Base>]
835- def inner_get_constants fqns , visibility , skip
836- return [ ] if fqns . nil? || skip . include? ( fqns )
837- skip . add fqns
838- result = [ ]
839- store . get_prepends ( fqns ) . each do |is |
840- result . concat inner_get_constants ( qualify ( is , fqns ) , [ :public ] , skip )
841- end
842- result . concat store . get_constants ( fqns , visibility )
843- . sort { |a , b | a . name <=> b . name }
844- store . get_includes ( fqns ) . each do |is |
845- result . concat inner_get_constants ( qualify ( is , fqns ) , [ :public ] , skip )
846- end
847- fqsc = qualify_superclass ( fqns )
848- unless %w[ Object BasicObject ] . include? ( fqsc )
849- result . concat inner_get_constants ( fqsc , [ :public ] , skip )
850- end
851- result
852- end
853-
854805 # @return [Hash]
855806 def path_macros
856807 @path_macros ||= { }
857808 end
858809
859- # @param namespace [String]
860- # @param context [String]
861- # @return [String, nil]
862- def qualify_lower namespace , context
863- qualify namespace , context . split ( '::' ) [ 0 ..-2 ] . join ( '::' )
864- end
865-
866810 # @param fq_sub_tag [String]
867811 # @return [String, nil]
868812 def qualify_superclass fq_sub_tag
869- fq_sub_type = ComplexType . try_parse ( fq_sub_tag )
870- fq_sub_ns = fq_sub_type . name
871- sup_tag = store . get_superclass ( fq_sub_tag )
872- sup_type = ComplexType . try_parse ( sup_tag )
873- sup_ns = sup_type . name
874- return nil if sup_tag . nil?
875- parts = fq_sub_ns . split ( '::' )
876- last = parts . pop
877- parts . pop if last == sup_ns
878- qualify ( sup_tag , parts . join ( '::' ) )
879- end
880-
881- # @param name [String] Namespace to fully qualify
882- # @param root [String] The context to search
883- # @param skip [Set<String>] Contexts already searched
884- # @return [String, nil] Fully qualified ("rooted") namespace
885- def inner_qualify name , root , skip
886- return name if name == ComplexType ::GENERIC_TAG_NAME
887- return nil if name . nil?
888- return nil if skip . include? ( root )
889- skip . add root
890- possibles = [ ]
891- if name == ''
892- if root == ''
893- return ''
894- else
895- return inner_qualify ( root , '' , skip )
896- end
897- else
898- return name if root == '' && store . namespace_exists? ( name )
899- roots = root . to_s . split ( '::' )
900- while roots . length > 0
901- fqns = roots . join ( '::' ) + '::' + name
902- return fqns if store . namespace_exists? ( fqns )
903- incs = store . get_includes ( roots . join ( '::' ) )
904- incs . each do |inc |
905- foundinc = inner_qualify ( name , inc , skip )
906- possibles . push foundinc unless foundinc . nil?
907- end
908- roots . pop
909- end
910- if possibles . empty?
911- incs = store . get_includes ( '' )
912- incs . each do |inc |
913- foundinc = inner_qualify ( name , inc , skip )
914- possibles . push foundinc unless foundinc . nil?
915- end
916- end
917- return name if store . namespace_exists? ( name )
918- return possibles . last
919- end
813+ store . qualify_superclass fq_sub_tag
920814 end
921815
922816 # Get the namespace's type (Class or Module).
@@ -1041,9 +935,9 @@ def should_erase_generics_when_done?(namespace_pin, rooted_type)
1041935 has_generics? ( namespace_pin ) && !can_resolve_generics? ( namespace_pin , rooted_type )
1042936 end
1043937
1044- # @param namespace_pin [Pin::Namespace]
938+ # @param namespace_pin [Pin::Namespace, Pin::Constant ]
1045939 def has_generics? ( namespace_pin )
1046- namespace_pin && !namespace_pin . generics . empty?
940+ namespace_pin . is_a? ( Pin :: Namespace ) && !namespace_pin . generics . empty?
1047941 end
1048942
1049943 # @param namespace_pin [Pin::Namespace]
0 commit comments