objc-dependency-tree-generator 0.0.8 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/objc_dependency_tree_generator +2 -2
- data/lib/dependency_tree.rb +119 -0
- data/lib/helpers/objc_dependency_tree_generator_helper.rb +58 -0
- data/lib/helpers/swift_primitives.rb +282 -0
- data/lib/{objc_dependencies_generator.rb → objc/objc_dependencies_generator.rb} +0 -0
- data/lib/objc_dependency_tree_generator.rb +106 -89
- data/lib/sourcekitten/sourcekitten_dependencies_generator.rb +229 -0
- data/lib/swift-ast-dump/swift_ast_dependencies_generator.rb +216 -0
- data/lib/swift-ast-dump/swift_ast_parser.rb +217 -0
- data/lib/{swift_dependencies_generator.rb → swift/swift_dependencies_generator.rb} +0 -0
- data/lib/tree_serializer.rb +64 -0
- metadata +14 -8
- data/lib/objc_dependency_tree_generator_helper.rb +0 -67
File without changes
|
@@ -1,13 +1,16 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
+
|
2
3
|
require 'optparse'
|
3
4
|
require 'yaml'
|
4
5
|
require 'json'
|
5
|
-
require 'objc_dependency_tree_generator_helper'
|
6
|
-
require 'swift_dependencies_generator'
|
7
|
-
require 'objc_dependencies_generator'
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
require 'helpers/objc_dependency_tree_generator_helper'
|
7
|
+
require 'swift/swift_dependencies_generator'
|
8
|
+
require 'objc/objc_dependencies_generator'
|
9
|
+
require 'sourcekitten/sourcekitten_dependencies_generator'
|
10
|
+
require 'dependency_tree'
|
11
|
+
require 'tree_serializer'
|
12
|
+
|
13
|
+
class DependencyTreeGenerator
|
11
14
|
def initialize(options)
|
12
15
|
@options = options
|
13
16
|
@options[:derived_data_project_pattern] = '*-*' unless @options[:derived_data_project_pattern]
|
@@ -19,125 +22,139 @@ class ObjCDependencyTreeGenerator
|
|
19
22
|
def self.parse_command_line_options
|
20
23
|
options = {}
|
21
24
|
|
22
|
-
#Defaults
|
25
|
+
# Defaults
|
23
26
|
options[:derived_data_paths] = ['~/Library/Developer/Xcode/DerivedData', '~/Library/Caches/appCode*/DerivedData']
|
24
27
|
options[:project_name] = ''
|
25
28
|
options[:output_format] = 'json'
|
29
|
+
options[:verbose] = true
|
30
|
+
options[:swift_ast_show_parsed_tree] = false
|
31
|
+
options[:ignore_primitive_types] = true
|
32
|
+
options[:show_inheritance_only] = false
|
26
33
|
|
27
|
-
|
28
|
-
parser = OptionParser.new do |o|
|
34
|
+
OptionParser.new do |o|
|
29
35
|
o.separator 'General options:'
|
30
|
-
o.on('-p PATH', '--path'
|
36
|
+
o.on('-p PATH', '--path', 'Path to directory where are your .o files were placed by the compiler', Array) do |directory|
|
31
37
|
options[:search_directories] = Array(options[:search_directories]) | Array(directory)
|
32
|
-
|
33
|
-
o.on('-D DERIVED_DATA', 'Path to directory where DerivedData is')
|
38
|
+
end
|
39
|
+
o.on('-D DERIVED_DATA', 'Path to directory where DerivedData is') do |derived_data|
|
34
40
|
options[:derived_data_paths] = [derived_data]
|
35
41
|
options[:derived_data_project_pattern] = '*'
|
36
|
-
|
37
|
-
o.on('-
|
42
|
+
end
|
43
|
+
o.on('-output PROJECT_NAME', 'Search project .o files by specified project name') do |project_name|
|
38
44
|
options[:project_name] = project_name
|
39
|
-
|
40
|
-
o.on('-t TARGET_NAME', '--target' 'Target of project', Array)
|
45
|
+
end
|
46
|
+
o.on('-t TARGET_NAME', '--target', 'Target of project', Array) do |target_name|
|
41
47
|
options[:target_names] = Array(options[:target_names]) | Array(target_name)
|
42
|
-
|
43
|
-
o.on('-e PREFIXES', "Prefixes of classes those will be exсluded from visualization. \n\t\t\t\t\tNS|UI\n\t\t\t\t\tUI|CA|MF")
|
48
|
+
end
|
49
|
+
o.on('-e PREFIXES', "Prefixes of classes those will be exсluded from visualization. \n\t\t\t\t\tNS|UI\n\t\t\t\t\tUI|CA|MF") do |exclusion_prefixes|
|
44
50
|
options[:exclusion_prefixes] = exclusion_prefixes
|
45
|
-
|
51
|
+
end
|
46
52
|
|
47
|
-
o.on('-d', '--use-dwarf-info', 'Use DWARF Information also')
|
53
|
+
o.on('-d', '--use-dwarf-info', 'Use DWARF Information also') do |v|
|
48
54
|
options[:use_dwarf] = v
|
49
|
-
|
50
|
-
|
55
|
+
end
|
56
|
+
|
57
|
+
o.on('-w', '--swift-dependencies', 'Generate swift project dependencies') do |v|
|
51
58
|
options[:swift_dependencies] = v
|
52
|
-
|
53
|
-
o.on('-
|
59
|
+
end
|
60
|
+
o.on('-k FILENAME', 'Generate dependencies from source kitten output (json)') do |v|
|
61
|
+
options[:sourcekitten_dependencies_file] = v
|
62
|
+
end
|
63
|
+
|
64
|
+
o.on('--ast-file FILENAME', 'Generate dependencies from the swift ast dump output (ast)') do |v|
|
65
|
+
options[:swift_ast_dump_file] = v
|
66
|
+
end
|
67
|
+
|
68
|
+
o.on('--ast-show-parsed-tree', 'Show ast parsing info (for swift ast parser only)') do |_v|
|
69
|
+
options[:swift_ast_show_parsed_tree] = true
|
70
|
+
end
|
71
|
+
|
72
|
+
o.on('--inheritance-only', 'Show only inheritance dependencies') do
|
73
|
+
options[:show_inheritance_only] = true
|
74
|
+
end
|
75
|
+
|
76
|
+
o.on('-f FORMAT', 'Output format. json by default. Possible values are [dot|json-pretty|json|json-var|yaml]') do |f|
|
54
77
|
options[:output_format] = f
|
55
|
-
|
78
|
+
end
|
79
|
+
o.on('-o OUTPUT_FILE', '--output', 'target of output') do |f|
|
80
|
+
options[:target_file_name] = f
|
81
|
+
end
|
56
82
|
|
57
83
|
o.separator 'Common options:'
|
58
|
-
o.on_tail('-h', 'Prints this help')
|
84
|
+
o.on_tail('-h', 'Prints this help') do
|
85
|
+
puts o
|
86
|
+
exit
|
87
|
+
end
|
59
88
|
o.parse!
|
60
|
-
|
61
89
|
end
|
62
90
|
|
63
91
|
options
|
92
|
+
end
|
64
93
|
|
94
|
+
def find_objecte_files_directories
|
95
|
+
find_project_output_directory(
|
96
|
+
@options[:derived_data_paths],
|
97
|
+
@options[:project_name],
|
98
|
+
@options[:derived_data_project_pattern],
|
99
|
+
@options[:target_names],
|
100
|
+
@options[:verbose]
|
101
|
+
)
|
65
102
|
end
|
66
103
|
|
67
|
-
def
|
68
|
-
|
69
|
-
|
70
|
-
|
104
|
+
def build_dependency_tree
|
105
|
+
tree = generate_depdendency_tree
|
106
|
+
tree.filter { |item, _| is_valid_dest?(item, @exclusion_prefixes) } if @options[:ignore_primitive_types]
|
107
|
+
tree.filter_links { |_ , _ , type | type == DependencyLinkType::INHERITANCE } if @options[:show_inheritance_only]
|
108
|
+
tree
|
109
|
+
end
|
71
110
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
@options[:target_names])
|
78
|
-
return {} unless @object_files_directories
|
79
|
-
end
|
111
|
+
def generate_depdendency_tree
|
112
|
+
return build_sourcekitten_dependency_tree if @options[:sourcekitten_dependencies_file]
|
113
|
+
return build_ast_dependency_tree if @options[:swift_ast_dump_file]
|
114
|
+
return tree_from_object_files_directory
|
115
|
+
end
|
80
116
|
|
81
|
-
|
82
|
-
|
83
|
-
exit 1
|
84
|
-
end
|
117
|
+
def tree_from_object_files_directory
|
118
|
+
tree = DependencyTree.new
|
85
119
|
|
120
|
+
return tree if !@options || @options.empty?
|
121
|
+
@object_files_directories ||= find_objecte_files_directories
|
122
|
+
return tree unless @object_files_directories
|
86
123
|
|
87
|
-
|
88
|
-
links_block = lambda { |source, dest|
|
89
|
-
links[source] = {} unless links[source]
|
90
|
-
if source != dest and is_valid_dest?(dest, @exclusion_prefixes)
|
91
|
-
links[source][dest] = 'set up'
|
92
|
-
end
|
93
|
-
}
|
94
|
-
|
124
|
+
update_tree_block = lambda { |source, target| tree.add(source, target) }
|
95
125
|
if @options[:swift_dependencies]
|
96
|
-
SwiftDependenciesGenerator.new.generate_dependencies(@object_files_directories, &
|
126
|
+
SwiftDependenciesGenerator.new.generate_dependencies(@object_files_directories, &update_tree_block)
|
97
127
|
else
|
98
|
-
ObjcDependenciesGenerator.new.generate_dependencies(@object_files_directories, @options[:use_dwarf], &
|
128
|
+
ObjcDependenciesGenerator.new.generate_dependencies(@object_files_directories, @options[:use_dwarf], &update_tree_block)
|
99
129
|
end
|
130
|
+
tree
|
131
|
+
end
|
132
|
+
|
133
|
+
def build_ast_dependency_tree
|
134
|
+
require_relative 'swift-ast-dump/swift_ast_dependencies_generator'
|
135
|
+
generator = SwiftAstDependenciesGenerator.new(
|
136
|
+
@options[:swift_ast_dump_file],
|
137
|
+
@options[:swift_ast_show_parsed_tree]
|
138
|
+
)
|
139
|
+
generator.generate_dependencies
|
140
|
+
end
|
100
141
|
|
101
|
-
|
142
|
+
def build_sourcekitten_dependency_tree
|
143
|
+
generator = SourcekittenDependenciesGenerator.new(
|
144
|
+
@options[:sourcekitten_dependencies_file]
|
145
|
+
)
|
146
|
+
generator.generate_dependencies
|
102
147
|
end
|
103
148
|
|
104
149
|
def dependencies_to_s
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
s+= <<-THEEND
|
109
|
-
var dependencies =
|
110
|
-
THEEND
|
111
|
-
end
|
150
|
+
tree = build_dependency_tree
|
151
|
+
serializer = TreeSerializer.new(tree)
|
152
|
+
output = serializer.serialize(@options[:output_format])
|
112
153
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
links_count = 0
|
117
|
-
links.each do |source, dest_hash|
|
118
|
-
links_count = links_count + dest_hash.length
|
119
|
-
dest_hash.each do |dest, _|
|
120
|
-
json_links += [{'source' => source, 'dest' => dest}]
|
121
|
-
end
|
122
|
-
end
|
123
|
-
json_result['links'] = json_links
|
124
|
-
json_result['source_files_count'] = links.length
|
125
|
-
json_result['links_count'] = links_count
|
126
|
-
|
127
|
-
if @options[:output_format] == 'dot'
|
128
|
-
indent = "\t"
|
129
|
-
s = "digraph dependencies {\n#{indent}node [fontname=monospace, fontsize=9, shape=box, style=rounded]\n"
|
130
|
-
json_links.each do |link|
|
131
|
-
s += "#{indent}\"#{link['source']}\" -> \"#{link['dest']}\"\n"
|
132
|
-
end
|
133
|
-
s += "}\n"
|
154
|
+
if @options[:target_file_name]
|
155
|
+
File.open(@options[:target_file_name], 'w').write(output.to_s)
|
134
156
|
else
|
135
|
-
|
136
|
-
s = s + json_result.to_json if @options[:output_format] == 'json' || @options[:output_format] == 'json-var'
|
137
|
-
s = s + json_result.to_yaml if @options[:output_format] == 'yaml'
|
157
|
+
output
|
138
158
|
end
|
139
|
-
s
|
140
159
|
end
|
141
|
-
|
142
|
-
|
143
|
-
end
|
160
|
+
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'helpers/objc_dependency_tree_generator_helper'
|
3
|
+
require 'rexml/document'
|
4
|
+
require 'helpers/swift_primitives'
|
5
|
+
|
6
|
+
module SKDeclarationType
|
7
|
+
SWIFT_EXTENSION = 'source.lang.swift.decl.extension'.freeze
|
8
|
+
SWIFT_PROTOCOL = 'source.lang.swift.decl.protocol'.freeze
|
9
|
+
SWIFT_STRUCT = 'source.lang.swift.decl.struct'.freeze
|
10
|
+
SWIFT_CLASS = 'source.lang.swift.decl.class'.freeze
|
11
|
+
OBJC_PROTOCOL = 'sourcekitten.source.lang.objc.decl.protocol'.freeze
|
12
|
+
OBJC_STRUCT = 'sourcekitten.source.lang.objc.decl.struct'.freeze
|
13
|
+
OBJC_CLASS = 'sourcekitten.source.lang.objc.decl.class'.freeze
|
14
|
+
|
15
|
+
|
16
|
+
INSTANCE_VARIABLE = 'source.lang.swift.decl.var.instance'.freeze
|
17
|
+
STATIC_VARIABLE = 'source.lang.swift.decl.var.static'.freeze
|
18
|
+
INSTANCE_METHOD = 'source.lang.swift.decl.function.method.instance'.freeze
|
19
|
+
CLASS_METHOD = 'source.lang.swift.decl.function.method.class'.freeze
|
20
|
+
CALL = 'source.lang.swift.expr.call'.freeze
|
21
|
+
ARGUMENT = 'source.lang.swift.expr.argument'.freeze
|
22
|
+
DICTIONARY = 'source.lang.swift.expr.dictionary'.freeze
|
23
|
+
ARRAY = 'source.lang.swift.expr.array'.freeze
|
24
|
+
end
|
25
|
+
|
26
|
+
module SKKey
|
27
|
+
SUBSTRUCTURE = 'key.substructure'.freeze
|
28
|
+
KIND = 'key.kind'.freeze
|
29
|
+
INHERITED_TYPES = 'key.inheritedtypes'.freeze
|
30
|
+
NAME = 'key.name'.freeze
|
31
|
+
TYPE_NAME = 'key.typename'.freeze
|
32
|
+
ANNOTATED_DECLARATION = 'key.annotated_decl'.freeze
|
33
|
+
FULLY_ANNOTATED_DECLARATION = 'key.fully_annotated_decl'.freeze
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
class SourcekittenDependenciesGenerator
|
38
|
+
|
39
|
+
def initialize(source_kitten_json)
|
40
|
+
@source_kitten_json = source_kitten_json
|
41
|
+
end
|
42
|
+
# @return [DependencyTree]
|
43
|
+
def generate_dependencies
|
44
|
+
|
45
|
+
@tree = DependencyTree.new
|
46
|
+
@context = []
|
47
|
+
|
48
|
+
file = File.read(@source_kitten_json)
|
49
|
+
parsed_files = JSON.parse(file)
|
50
|
+
|
51
|
+
parsed_files.each do |parsed_file|
|
52
|
+
parsed_file.each do |_path, contents|
|
53
|
+
substructures = contents[SKKey::SUBSTRUCTURE] || next
|
54
|
+
substructures.each { |substructure| parse_structure(substructure) }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
@tree
|
59
|
+
end
|
60
|
+
|
61
|
+
def in_context(name)
|
62
|
+
@context.push(name)
|
63
|
+
yield
|
64
|
+
@context.pop
|
65
|
+
end
|
66
|
+
|
67
|
+
# @param [Hash] item array of sourcekitten substructure of class, protocol, whatever
|
68
|
+
# @param [DependencyItemType] type type of items to register
|
69
|
+
def register_item(item, type)
|
70
|
+
item_name = item[SKKey::NAME]
|
71
|
+
@tree.register(item_name, type)
|
72
|
+
|
73
|
+
inherited_types = item[SKKey::INHERITED_TYPES] || return
|
74
|
+
|
75
|
+
inherited_types.each do |inherited_type|
|
76
|
+
inherited_type_name = inherited_type[SKKey::NAME]
|
77
|
+
@tree.add(item_name, inherited_type_name)
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
# @param [Hash] element SourceKitten source
|
83
|
+
def parse_structure(element)
|
84
|
+
|
85
|
+
kind = element[SKKey::KIND]
|
86
|
+
item_name = element[SKKey::NAME]
|
87
|
+
|
88
|
+
case kind
|
89
|
+
when SKDeclarationType::SWIFT_EXTENSION
|
90
|
+
process_element(element, DependencyItemType::UNKNOWN)
|
91
|
+
|
92
|
+
when SKDeclarationType::SWIFT_PROTOCOL, SKDeclarationType::OBJC_PROTOCOL
|
93
|
+
process_element(element, DependencyItemType::PROTOCOL)
|
94
|
+
|
95
|
+
when SKDeclarationType::SWIFT_STRUCT, SKDeclarationType::OBJC_STRUCT
|
96
|
+
process_element(element, DependencyItemType::STRUCTURE)
|
97
|
+
|
98
|
+
when SKDeclarationType::SWIFT_CLASS, SKDeclarationType::OBJC_CLASS
|
99
|
+
process_element(element, DependencyItemType::CLASS)
|
100
|
+
register_types_from_annotated_declaration(element)
|
101
|
+
|
102
|
+
when SKDeclarationType::INSTANCE_VARIABLE, SKDeclarationType::INSTANCE_METHOD, SKDeclarationType::STATIC_VARIABLE, SKDeclarationType::CLASS_METHOD
|
103
|
+
@context.each do |el_name|
|
104
|
+
register_types_from_annotated_declaration(element, el_name)
|
105
|
+
end
|
106
|
+
parse_substructures(element)
|
107
|
+
|
108
|
+
when SKDeclarationType::CALL
|
109
|
+
if item_name
|
110
|
+
object_names = potential_object_names(item_name)
|
111
|
+
object_names.each { |on| @context.each { |el_name| @tree.add(el_name, on, DependencyLinkType::CALL)} }
|
112
|
+
end
|
113
|
+
parse_substructures(element)
|
114
|
+
|
115
|
+
when SKDeclarationType::ARGUMENT, SKDeclarationType::DICTIONARY, SKDeclarationType::ARRAY
|
116
|
+
parse_substructures(element)
|
117
|
+
|
118
|
+
else
|
119
|
+
# do nothing
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# @param [Hash] item array of sourcekitten substructure of class, protocol, whatever
|
124
|
+
# @param [DependencyItemType] type type of items to register
|
125
|
+
def process_element(element, type)
|
126
|
+
register_item(element, type)
|
127
|
+
item_name = element[SKKey::NAME] || return
|
128
|
+
link_items_from_context(item_name)
|
129
|
+
in_context(item_name) do
|
130
|
+
parse_substructures(element)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def parse_substructures(element)
|
135
|
+
sub_structures = element[SKKey::SUBSTRUCTURE] || return
|
136
|
+
sub_structures.each { |it| parse_structure(it) }
|
137
|
+
end
|
138
|
+
|
139
|
+
def link_items_from_context(item_name)
|
140
|
+
@context.each { |el_name| @tree.add(el_name, item_name) }
|
141
|
+
end
|
142
|
+
|
143
|
+
def register_types_from_annotated_declaration(element, name = nil)
|
144
|
+
item_name = name || element[SKKey::NAME] || return
|
145
|
+
annotated_decl = element[SKKey::ANNOTATED_DECLARATION] || return
|
146
|
+
|
147
|
+
doc = REXML::Document.new(annotated_decl)
|
148
|
+
|
149
|
+
has_typealiases = false
|
150
|
+
doc.each_element('//Declaration/Type') do |el|
|
151
|
+
dependency_type = el.text.to_s
|
152
|
+
|
153
|
+
# get el type
|
154
|
+
attribute_el = el.attribute('usr') || next
|
155
|
+
|
156
|
+
if is_typealias(element, dependency_type)
|
157
|
+
has_typealiases = true
|
158
|
+
next
|
159
|
+
end
|
160
|
+
|
161
|
+
attribute = attribute_el.to_s
|
162
|
+
if attribute.start_with? 's:P'
|
163
|
+
@tree.add(item_name, dependency_type)
|
164
|
+
@tree.register(dependency_type, DependencyItemType::PROTOCOL)
|
165
|
+
elsif attribute.start_with? 'c:objc(pl)'
|
166
|
+
@tree.add(item_name, dependency_type)
|
167
|
+
@tree.register(dependency_type, DependencyItemType::PROTOCOL)
|
168
|
+
elsif attribute.start_with? 'c:objc(cs)'
|
169
|
+
@tree.add(item_name, dependency_type)
|
170
|
+
@tree.register(dependency_type, DependencyItemType::CLASS)
|
171
|
+
elsif attribute.start_with? 's:C'
|
172
|
+
@tree.add(item_name, dependency_type)
|
173
|
+
@tree.register(dependency_type, DependencyItemType::CLASS)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
register_types_from_type_name(element, item_name) if has_typealiases
|
178
|
+
end
|
179
|
+
|
180
|
+
def register_types_from_type_name(element, item_name)
|
181
|
+
type_name_string = element[SKKey::TYPE_NAME] || return
|
182
|
+
|
183
|
+
generics = generic_parameters(element)
|
184
|
+
type_names(type_name_string)
|
185
|
+
.select { |type_name| !generics.include?(type_name) }
|
186
|
+
.each { |type_name| @tree.add(item_name, type_name) }
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
# @return [Array<String>] array of generic names for element
|
191
|
+
def generic_parameters(element)
|
192
|
+
fully_annotated_decl = element[SKKey::FULLY_ANNOTATED_DECLARATION]
|
193
|
+
return [] if fully_annotated_decl.nil?
|
194
|
+
generics = []
|
195
|
+
doc = REXML::Document.new(fully_annotated_decl)
|
196
|
+
doc.each_element('//decl.generic_type_param.name') do |el|
|
197
|
+
generics.push(el.text.to_s)
|
198
|
+
end
|
199
|
+
generics
|
200
|
+
end
|
201
|
+
|
202
|
+
def is_typealias(element, name)
|
203
|
+
fully_annotated_decl = element[SKKey::FULLY_ANNOTATED_DECLARATION]
|
204
|
+
return false if fully_annotated_decl.nil?
|
205
|
+
doc = REXML::Document.new(fully_annotated_decl)
|
206
|
+
doc.each_element('//ref.typealias') do |el|
|
207
|
+
return true if el.text.to_s == name
|
208
|
+
end
|
209
|
+
|
210
|
+
false
|
211
|
+
end
|
212
|
+
|
213
|
+
# Returns an array of strings, which represents type names
|
214
|
+
# @param [String] type_name_string sourcekitten type name
|
215
|
+
# @return [Array<String>] array of types, found in this type
|
216
|
+
def type_names(type_name_string)
|
217
|
+
type_name_string
|
218
|
+
.split(/\W+/)
|
219
|
+
.select { |t| !t.empty? }
|
220
|
+
.select { |t| !is_primitive_swift_type?(t) }
|
221
|
+
end
|
222
|
+
|
223
|
+
def potential_object_names(call_string)
|
224
|
+
(call_string.scan(/^[A-Z_][A-Za-z0-9_]+/) + call_string.scan(/\s[A-Z_][A-Za-z0-9_]+/))
|
225
|
+
.select { |t| !t.empty? }
|
226
|
+
.select { |t| !is_primitive_swift_type?(t) }
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|