Class: SwiftAstDependenciesGenerator

Inherits:
Object
  • Object
show all
Defined in:
lib/swift-ast-dump/swift_ast_dependencies_generator.rb

Instance Method Summary collapse

Constructor Details

#initialize(ast_file, dump_parsed_tree, verbose = false) ⇒ SwiftAstDependenciesGenerator

Returns a new instance of SwiftAstDependenciesGenerator.



6
7
8
9
10
# File 'lib/swift-ast-dump/swift_ast_dependencies_generator.rb', line 6

def initialize(ast_file, dump_parsed_tree, verbose = false)
  @ast_file = ast_file
  @verbose = verbose
  @dump_parsed_tree = dump_parsed_tree
end

Instance Method Details

#add_tree_dependency(from_name, to_name, type) ⇒ Object



199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/swift-ast-dump/swift_ast_dependencies_generator.rb', line 199

def add_tree_dependency(from_name, to_name, type) 
  # skip names from generics
  # we also will need to skip generics_from_functions
  skip_names = (@generics_context || []).flatten

  from = normalized_name(from_name)
  return if skip_names.include? from

  to = normalized_name(to_name)
  return if skip_names.include? to

  return unless to
  return unless from
  @tree.add(from, to, type)
end

#generate_dependenciesDependencyTree

Returns:



13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/swift-ast-dump/swift_ast_dependencies_generator.rb', line 13

def generate_dependencies

  @tree = DependencyTree.new
  @context = []
  @generics_context = []

  @ast_tree = SwiftAST::Parser.new().parse_build_log_output(File.read(@ast_file))
  @ast_tree.dump if @dump_parsed_tree
  scan_source_files

  @tree
end

#normalized_name(the_name) ⇒ Object



195
196
197
# File 'lib/swift-ast-dump/swift_ast_dependencies_generator.rb', line 195

def normalized_name(the_name)
  the_name.sub("inout ", "")[/(\w|\d|\.)+/]
end

#register_calls(node, name) ⇒ Object



160
161
162
163
164
165
166
# File 'lib/swift-ast-dump/swift_ast_dependencies_generator.rb', line 160

def register_calls(node, name)
  node.on_node("call_expr") { |variable|
    next unless type_decl = variable.parameters.find { |el| el.start_with?("type=") }
    type_name = type_decl.sub("type=", '')[1..-2].chomp("?")
    add_tree_dependency(name, type_name, DependencyLinkType::CALL)
  }
end

#register_function_parameters(node, name) ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/swift-ast-dump/swift_ast_dependencies_generator.rb', line 168

def register_function_parameters(node, name)  
  node.on_node("func_decl") { |func_decl|

    generic_names = register_generic_parameters(func_decl, name)
    @generics_context << generic_names

    func_decl.on_node("parameter_list") { |param_list|
      param_list.on_node("parameter") { |parameter|
        next unless type_decl = parameter.parameters.find { |el| el.start_with?("type=") }
        type_name = type_decl.sub("type=", '')[1..-2].chomp("?")
        add_tree_dependency(name, type_name, DependencyLinkType::PARAMETER)
      }
    }

    func_decl.on_node("result") { |result_decl|
      result_decl.on_node("type_ident") { |type_id|
        type_id.on_node("component") { |comp|
          next unless type_decl = comp.parameters.find { |el| el.start_with?("id=") }
          type_name = type_decl.sub("id=", '')[1..-2].chomp("?")
          add_tree_dependency(name, type_name, DependencyLinkType::PARAMETER)
        }
      }
    }
    @generics_context.pop
  }
end

#register_generic_parameters(node, name) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/swift-ast-dump/swift_ast_dependencies_generator.rb', line 120

def register_generic_parameters(node, name)
  return [] unless generic = node.parameters[1] # Second parameter
  return [] unless generic[0] + generic[-1] == "<>" 

  # REmove brackets
  generic = generic[1..-2]

  generic_decls = []
  generic.split(",").each { |decl|
    parts = decl.split(":")
    leftPart = parts[0]
    rightPart = parts[1]

    next unless leftPart

    generic_name = leftPart.strip || leftPart
    generic_decls << generic_name

    next unless rightPart


    rightPart.split("&").each { |protocol_or_class|
      proto_name = protocol_or_class.strip || protocol_or_class
      add_tree_dependency(name, proto_name, DependencyLinkType::INHERITANCE)
    }
  }

  generic_decls
end

#register_inheritance(node, name) ⇒ Object



102
103
104
105
106
107
108
109
# File 'lib/swift-ast-dump/swift_ast_dependencies_generator.rb', line 102

def register_inheritance(node, name)
  inheritance = node.parameters.drop_while { |el| el != "inherits:" }
  inheritance = inheritance.drop(1)
  inheritance.each { |inh| 
    inh_name = inh.chomp(",")
    add_tree_dependency(name, inh_name, DependencyLinkType::INHERITANCE)
  }
end

#register_typealiases(node, name) ⇒ Object



111
112
113
114
115
116
117
118
# File 'lib/swift-ast-dump/swift_ast_dependencies_generator.rb', line 111

def register_typealiases(node, name)
  node.on_node("typealias") { |typealias|
    typealias.parameters.select { |el| el.start_with?("type=") }.each { |type_decl|
      type_name = type_decl.sub("type=", '')[1..-2].chomp("?")
      add_tree_dependency(name, type_name, DependencyLinkType::PARAMETER)
    }
  }
end

#register_variables(node, name) ⇒ Object



151
152
153
154
155
156
157
# File 'lib/swift-ast-dump/swift_ast_dependencies_generator.rb', line 151

def register_variables(node, name)  
  node.on_node("var_decl") { |variable|
    next unless type_decl = variable.parameters.find { |el| el.start_with?("type=") }
    type_name = type_decl.sub("type=", '')[1..-2].chomp("?")
    add_tree_dependency(name, type_name, DependencyLinkType::IVAR)
  }
end

#scan_source_filesObject



26
27
28
29
30
31
32
33
# File 'lib/swift-ast-dump/swift_ast_dependencies_generator.rb', line 26

def scan_source_files
  source_files = @ast_tree.find_nodes("source_file")
  return scan_source_files_classes(@ast_tree) if source_files.empty?

  source_files.each { |source_file|
    scan_source_files_classes(source_file)       
  }
end

#scan_source_files_classes(root) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/swift-ast-dump/swift_ast_dependencies_generator.rb', line 35

def scan_source_files_classes(root)
  classes = root.find_nodes("class_decl")
  classes.each { |node| 
    next unless classname = node.parameters.first
    @tree.register(classname, DependencyItemType::CLASS) 
  }

  protocols = @ast_tree.find_nodes("protocol")
  protocols.each { |node| 
    next unless protoname = node.parameters.first
    @tree.register(protoname, DependencyItemType::PROTOCOL) 
  }

  structs = @ast_tree.find_nodes("struct_decl")
  structs.each { |node| 
    next unless struct_name = node.parameters.first
    @tree.register(struct_name, DependencyItemType::STRUCTURE) 
  }

  classes.each { |node| 
    next unless classname = node.parameters.first
    generic_names = register_generic_parameters(node, classname) 
    @generics_context << generic_names
    register_typealiases(node, classname)

    register_inheritance(node, classname) 
    register_variables(node, classname) 
    register_calls(node, classname) 
    register_function_parameters(node, classname) 

    @generics_context.pop

  }

  protocols.each { |node|
    return unless proto_name = node.parameters.first
    generic_names = register_generic_parameters(node, proto_name) 
    @generics_context << generic_names

    register_inheritance(node, proto_name) 
    register_function_parameters(node, proto_name) 
    @generics_context.pop

  }

  structs.each { |node|
    next unless classname = node.parameters.first
    generic_names = register_generic_parameters(node, classname) 
    @generics_context << generic_names
    register_typealiases(node, classname)

    register_inheritance(node, classname) 
    register_variables(node, classname) 
    register_calls(node, classname) 
    register_function_parameters(node, classname) 

    @generics_context.pop
  }

  extensions = @ast_tree.find_nodes("extension_decl")
  extensions.each { |node|
    return unless extension_name = node.parameters.first
    register_inheritance(node, extension_name) 
  }

end