Merge lp:~monkey-libre/valide/update-afrodite into lp:valide

Proposed by Monkey
Status: Merged
Merged at revision: 595
Proposed branch: lp:~monkey-libre/valide/update-afrodite
Merge into: lp:valide
Diff against target: 2247 lines (+774/-610)
13 files modified
plugins/completion/afrodite-provider/afrodite-provider.vala (+27/-36)
plugins/completion/afrodite-provider/afrodite/Makefile.am (+1/-1)
plugins/completion/afrodite-provider/afrodite/afroditetest.vala (+122/-115)
plugins/completion/afrodite-provider/afrodite/ast.vala (+9/-38)
plugins/completion/afrodite-provider/afrodite/astdumper.vala (+1/-1)
plugins/completion/afrodite-provider/afrodite/astmerger.vala (+299/-156)
plugins/completion/afrodite-provider/afrodite/completionengine.vala (+202/-199)
plugins/completion/afrodite-provider/afrodite/parser.vala (+10/-11)
plugins/completion/afrodite-provider/afrodite/parseresult.vala (+5/-0)
plugins/completion/afrodite-provider/afrodite/sourcefile.vala (+2/-25)
plugins/completion/afrodite-provider/afrodite/sourcereference.vala (+6/-6)
plugins/completion/afrodite-provider/afrodite/symbol.vala (+27/-14)
plugins/completion/afrodite-provider/afrodite/symbolresolver.vala (+63/-8)
To merge this branch: bzr merge lp:~monkey-libre/valide/update-afrodite
Reviewer Review Type Date Requested Status
Val(a)IDE Team Pending
Review via email: mp+52905@code.launchpad.net

Description of the change

Update Afrodite from vtg-0.11.1
Changes in the api:
Removed the try_acquire_ast / release_ast

Works very fast and without any problem. More info attached in the bug.
Thanks in advance.

To post a comment you must log in.
Revision history for this message
Monkey (monkey-libre) wrote :

Check this a lot because Afrodite could crash but I cannot reproduce it.

Thanks in advance.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'plugins/completion/afrodite-provider/afrodite-provider.vala'
--- plugins/completion/afrodite-provider/afrodite-provider.vala 2011-02-20 14:12:17 +0000
+++ plugins/completion/afrodite-provider/afrodite-provider.vala 2011-03-10 19:26:24 +0000
@@ -737,40 +737,35 @@
737 first_part = word; // "this"; //HACK: this won't work for static methods737 first_part = word; // "this"; //HACK: this won't work for static methods
738 }738 }
739739
740 Afrodite.Ast ast;740 Afrodite.Ast ast = completion.ast;
741 Afrodite.Symbol? symbol = null;741 Afrodite.Symbol? symbol = null;
742742 Afrodite.QueryResult? result = null;
743 if (this.completion.try_acquire_ast (out ast, retry_count))743 Afrodite.QueryOptions options = this.get_options_for_line (text, is_assignment, is_creation);
744 {744
745 Afrodite.QueryResult? result = null;745 if (word == symbol_name)
746 Afrodite.QueryOptions options = this.get_options_for_line (text, is_assignment, is_creation);746 {
747747 result = this.get_symbol_for_name (options, ast, first_part, null, line, col);
748 }
749 else
750 {
751 result = this.get_symbol_type_for_name (options, ast, first_part, null, line, col);
752 }
753
754 if (result != null && !result.is_empty)
755 {
756 var first = result.children.get (0);
748 if (word == symbol_name)757 if (word == symbol_name)
749 {758 {
750 result = this.get_symbol_for_name (options, ast, first_part, null, line, col);759 symbol = first.symbol;
751 }760 }
752 else761 else
753 {762 {
754 result = this.get_symbol_type_for_name (options, ast, first_part, null, line, col);763 symbol = this.get_symbol_for_name_in_children (symbol_name, first.symbol);
755 }764 if (symbol == null)
756765 {
757 if (result != null && !result.is_empty)766 symbol =this.get_symbol_for_name_in_base_types (symbol_name, first.symbol);
758 {767 }
759 var first = result.children.get (0);768 }
760 if (word == symbol_name)
761 {
762 symbol = first.symbol;
763 }
764 else
765 {
766 symbol = this.get_symbol_for_name_in_children (symbol_name, first.symbol);
767 if (symbol == null)
768 {
769 symbol =this.get_symbol_for_name_in_base_types (symbol_name, first.symbol);
770 }
771 }
772 }
773 this.completion.release_ast (ast);
774 }769 }
775 return symbol;770 return symbol;
776 }771 }
@@ -857,10 +852,9 @@
857852
858 Vtg.ParserUtils.parse_line (text, out word, out is_assignment, out is_creation, out is_declaration);853 Vtg.ParserUtils.parse_line (text, out word, out is_assignment, out is_creation, out is_declaration);
859854
860 Afrodite.Ast ast = null;855 Afrodite.Ast ast = completion.ast;
861 Vtg.Utils.trace ("completing word: '%s'", word);856 Vtg.Utils.trace ("completing word: '%s'", word);
862 if (!Vtg.StringUtils.is_null_or_empty (word)857 if (!Vtg.StringUtils.is_null_or_empty (word))
863 && this.completion.try_acquire_ast (out ast))
864 {858 {
865 Afrodite.QueryOptions options = this.get_options_for_line (text, is_assignment, is_creation);859 Afrodite.QueryOptions options = this.get_options_for_line (text, is_assignment, is_creation);
866 Afrodite.QueryResult result = null;860 Afrodite.QueryResult result = null;
@@ -878,7 +872,6 @@
878 }872 }
879 result = this.get_symbol_type_for_name (options, ast, word, text, line, col);873 result = this.get_symbol_type_for_name (options, ast, word, text, line, col);
880 this.transform_result (options, result);874 this.transform_result (options, result);
881 this.completion.release_ast (ast);
882 }875 }
883 else876 else
884 {877 {
@@ -895,12 +888,11 @@
895888
896 private void lookup_visible_symbols_in_scope (string word, Afrodite.CompareMode mode)889 private void lookup_visible_symbols_in_scope (string word, Afrodite.CompareMode mode)
897 {890 {
898 Afrodite.Ast ast = null;891 Afrodite.Ast ast = completion.ast;
899 Vtg.Utils.trace ("lookup_all_symbols_in_scope: mode: %s word:'%s' ",892 Vtg.Utils.trace ("lookup_all_symbols_in_scope: mode: %s word:'%s' ",
900 mode == Afrodite.CompareMode.EXACT ? "exact" : "start-with",893 mode == Afrodite.CompareMode.EXACT ? "exact" : "start-with",
901 word);894 word);
902 if (!Vtg.StringUtils.is_null_or_empty (word)895 if (!Vtg.StringUtils.is_null_or_empty (word))
903 && this.completion.try_acquire_ast (out ast, 0))
904 {896 {
905 Vala.List<Afrodite.Symbol> results = new Vala.ArrayList<Afrodite.Symbol> ();897 Vala.List<Afrodite.Symbol> results = new Vala.ArrayList<Afrodite.Symbol> ();
906898
@@ -929,7 +921,6 @@
929 this.proposals = new List<Gtk.SourceCompletionItem> ();921 this.proposals = new List<Gtk.SourceCompletionItem> ();
930 append_symbols (null, results);922 append_symbols (null, results);
931 }923 }
932 this.completion.release_ast (ast);
933 }924 }
934 else925 else
935 {926 {
936927
=== modified file 'plugins/completion/afrodite-provider/afrodite/Makefile.am'
--- plugins/completion/afrodite-provider/afrodite/Makefile.am 2010-10-14 16:01:50 +0000
+++ plugins/completion/afrodite-provider/afrodite/Makefile.am 2011-03-10 19:26:24 +0000
@@ -61,7 +61,7 @@
61 touch $@61 touch $@
6262
63libafrodite_la_LDFLAGS = \63libafrodite_la_LDFLAGS = \
64 -version-info 0:1:0 \64 -version-info 1:0:0 \
65 $(NULL)65 $(NULL)
6666
67libafrodite_la_LIBADD = \67libafrodite_la_LIBADD = \
6868
=== modified file 'plugins/completion/afrodite-provider/afrodite/afroditetest.vala'
--- plugins/completion/afrodite-provider/afrodite/afroditetest.vala 2010-10-14 16:01:50 +0000
+++ plugins/completion/afrodite-provider/afrodite/afroditetest.vala 2011-03-10 19:26:24 +0000
@@ -47,10 +47,11 @@
47};47};
4848
49public class AfroditeTest.Application : Object {49public class AfroditeTest.Application : Object {
50
51 private MainLoop _loop;
52 private Afrodite.CompletionEngine _engine;
53
50 public int run (string[] args) {54 public int run (string[] args) {
51 int i = 0;
52 int result = 0;
53
54 // parse options55 // parse options
55 var opt_context = new OptionContext ("- Afrodite Test");56 var opt_context = new OptionContext ("- Afrodite Test");
56 opt_context.set_help_enabled (true);57 opt_context.set_help_enabled (true);
@@ -60,12 +61,119 @@
60 } catch (Error err) {61 } catch (Error err) {
61 error (_("parsing options"));62 error (_("parsing options"));
62 }63 }
63 64
64 var engine = new Afrodite.CompletionEngine ("afrodite-test-engine");
65
66 if (option_repeat == 0)65 if (option_repeat == 0)
67 option_repeat = 1;66 option_repeat = 1;
68 67
68 parse ();
69 _loop = new MainLoop();
70 _loop.run();
71 return 0;
72 }
73
74 private void on_begin_parsing (CompletionEngine engine)
75 {
76 print ("\nAfrodite engine is parsing sources\n");
77 }
78 private void on_end_parsing (CompletionEngine engine)
79 {
80 print ("\nAfrodite engine end parsing sources\n");
81 _loop.quit ();
82 dump (engine);
83 }
84
85 private void dump (CompletionEngine engine)
86 {
87 print (": done\n\n");
88 print ("Looking for '%s' %d,%d\n\nDump follows:\n", option_symbol_name, option_line, option_column);
89 while (true)
90 {
91 // dumping tree (just a debug facility)
92 var dumper = new Afrodite.AstDumper ();
93 dumper.dump (engine.ast, option_namespace);
94 print ("\n");
95
96 // Query the AST
97 if (option_visible_symbols != null) {
98 var source = engine.ast.lookup_source_file (option_visible_symbols);
99 if (source != null) {
100 // get the source node at this position
101 var s = engine.ast.get_symbol_for_source_and_position (source, option_line, option_column);
102 if (s != null) {
103 Vala.List<Symbol> syms = null;
104 syms = engine.ast.lookup_visible_symbols_from_symbol (s, option_filter);
105 print ("Symbols found: %d\n", syms.size);
106 foreach (Symbol sym in syms) {
107 print (" from %s: %s\n", sym.parent == null ? "<root>" : sym.parent.fully_qualified_name, Utils.unescape_xml_string (sym.description));
108 }
109 } else {
110 print ("no symbol found for position: %d-%d\n", option_line, option_column);
111 }
112 } else {
113 print ("source file not found: %s\n", option_visible_symbols);
114 }
115 } else if (option_symbol_name != null) {
116 // Setup query options
117 QueryOptions options = QueryOptions.standard ();
118 options.auto_member_binding_mode = true;
119 options.compare_mode = CompareMode.EXACT;
120 options.access = Afrodite.SymbolAccessibility.ANY;
121 options.binding = Afrodite.MemberBinding.ANY;
122
123 QueryResult sym = null;
124 sym = engine.ast.get_symbol_type_for_name_and_path (options, option_symbol_name, option_files[0], option_line, option_column);
125 print ("The type for '%s' is: ", option_symbol_name);
126 if (!sym.is_empty) {
127 foreach (ResultItem item in sym.children) {
128 print ("%s\n Childs:\n", Utils.unescape_xml_string (item.symbol.description));
129 if (item.symbol.has_children) {
130 int count = 0;
131 // print an excerpt of the child symbols
132 foreach (var child in item.symbol.children) {
133 print (" %s\n", Utils.unescape_xml_string (child.description));
134 count++;
135 if (count == 6) {
136 print (" ......\n");
137 break;
138 }
139 }
140 if (count < 6 && item.symbol.has_base_types) {
141 foreach (var base_item in item.symbol.base_types) {
142 if (base_item.unresolved || !base_item.symbol.has_children)
143 continue;
144
145 foreach (var child in base_item.symbol.children) {
146 print (" %s\n", Utils.unescape_xml_string (child.description));
147 count++;
148 if (count == 6)
149 break;
150 }
151
152 if (count == 6) {
153 print (" ......\n");
154 break;
155 }
156 }
157 }
158 }
159 }
160 } else {
161 print ("unresolved :(\n");
162 }
163 }
164 break;
165 }
166
167 print ("done\n");
168 }
169
170 private void parse () {
171 int i = 0;
172
173 _engine = new Afrodite.CompletionEngine ("afrodite-test-engine");
174 _engine.begin_parsing.connect (this.on_begin_parsing);
175 _engine.end_parsing.connect (this.on_end_parsing);
176
69 for(int repeat = 0; repeat < option_repeat; repeat++) {177 for(int repeat = 0; repeat < option_repeat; repeat++) {
70 print ("Adding sources (%d):\n", repeat);178 print ("Adding sources (%d):\n", repeat);
71 i = 0;179 i = 0;
@@ -82,118 +190,17 @@
82 }190 }
83 source.content = buffer;191 source.content = buffer;
84 source.path = "live-buffer.vala";192 source.path = "live-buffer.vala";
85 engine.queue_source (source);193 _engine.queue_source (source);
86 } else {194 } else {
87 engine.queue_sourcefile (filename);195 _engine.queue_sourcefile (filename);
88 }196 }
89 i++;197 i++;
90 }198 }
91199 }
92 print ("\nAfrodite engine is parsing sources (%d)", repeat);
93 // Wait for the engine to complete the parsing
94 i = 0;
95 while (engine.is_parsing)
96 {
97 if (i % 10 == 0)
98 print (".");
99 Thread.usleep (1 * 250000);
100 i++;
101 }
102 }
103
104 Afrodite.Ast ast;
105 print (": done\n\n");
106 print ("Looking for '%s' %d,%d\n\nDump follows:\n", option_symbol_name, option_line, option_column);
107 while (true)
108 {
109 // try to acquire ast
110 if (engine.try_acquire_ast (out ast)) {
111 // dumping tree (just a debug facility)
112 var dumper = new Afrodite.AstDumper ();
113 dumper.dump (ast, option_namespace);
114 print ("\n");
115
116 // Query the AST
117 if (option_visible_symbols != null) {
118 var source = ast.lookup_source_file (option_visible_symbols);
119 if (source != null) {
120 // get the source node at this position
121 var s = ast.get_symbol_for_source_and_position (source, option_line, option_column);
122 if (s != null) {
123 Vala.List<Symbol> syms = null;
124 syms = ast.lookup_visible_symbols_from_symbol (s, option_filter);
125 print ("Symbols found: %d\n", syms.size);
126 foreach (Symbol sym in syms) {
127 print (" from %s: %s\n", sym.parent == null ? "<root>" : sym.parent.fully_qualified_name, Utils.unescape_xml_string (sym.description));
128 }
129 } else {
130 print ("no symbol found for position: %d-%d\n", option_line, option_column);
131 }
132 } else {
133 print ("source file not found: %s\n", option_visible_symbols);
134 }
135 } else if (option_symbol_name != null) {
136 // Setup query options
137 QueryOptions options = QueryOptions.standard ();
138 options.auto_member_binding_mode = true;
139 options.compare_mode = CompareMode.EXACT;
140 options.access = Afrodite.SymbolAccessibility.ANY;
141 options.binding = Afrodite.MemberBinding.ANY;
142
143 QueryResult sym = null;
144 sym = ast.get_symbol_type_for_name_and_path (options, option_symbol_name, option_files[0], option_line, option_column);
145 print ("The type for '%s' is: ", option_symbol_name);
146 if (!sym.is_empty) {
147 foreach (ResultItem item in sym.children) {
148 print ("%s\n Childs:\n", Utils.unescape_xml_string (item.symbol.description));
149 if (item.symbol.has_children) {
150 int count = 0;
151 // print an excerpt of the child symbols
152 foreach (var child in item.symbol.children) {
153 print (" %s\n", Utils.unescape_xml_string (child.description));
154 count++;
155 if (count == 6) {
156 print (" ......\n");
157 break;
158 }
159 }
160 if (count < 6 && item.symbol.has_base_types) {
161 foreach (var base_item in item.symbol.base_types) {
162 if (base_item.unresolved || !base_item.symbol.has_children)
163 continue;
164
165 foreach (var child in base_item.symbol.children) {
166 print (" %s\n", Utils.unescape_xml_string (child.description));
167 count++;
168 if (count == 6)
169 break;
170 }
171
172 if (count == 6) {
173 print (" ......\n");
174 break;
175 }
176 }
177 }
178 }
179 }
180 } else {
181 print ("unresolved :(\n");
182 result = 1;
183 }
184 }
185 engine.release_ast (ast);
186 break;
187 }
188 }
189
190 print ("done\n");
191 return result;
192 }200 }
193201
194 static int main (string[] args) {202 static int main (string[] args) {
195 var application = new Application ();203 var application = new Application ();
196 application.run (args);204 return application.run (args);
197 return 0;
198 }205 }
199}206}
200207
=== modified file 'plugins/completion/afrodite-provider/afrodite/ast.vala'
--- plugins/completion/afrodite-provider/afrodite/ast.vala 2010-10-14 16:01:50 +0000
+++ plugins/completion/afrodite-provider/afrodite/ast.vala 2011-03-10 19:26:24 +0000
@@ -26,32 +26,17 @@
26{26{
27 public class Ast27 public class Ast
28 {28 {
29
30#if DEBUG
31 // debug utility to dump leaked symbols when destroying a source file
32 public static Vala.List<unowned Symbol> leaked_symbols = new Vala.ArrayList<unowned Symbol>();
33#endif
34 public Vala.HashMap<string, unowned Symbol> symbols = new Vala.HashMap <string, unowned Symbol>(GLib.str_hash, GLib.str_equal);29 public Vala.HashMap<string, unowned Symbol> symbols = new Vala.HashMap <string, unowned Symbol>(GLib.str_hash, GLib.str_equal);
3530 public Vala.List<unowned Symbol> unresolved_symbols = new Vala.ArrayList<unowned Symbol>();
31
36 private Symbol _root = new Symbol (null, null);32 private Symbol _root = new Symbol (null, null);
3733
38 ~Ast ()34 ~Ast ()
39 {35 {
40 Utils.trace ("Ast destroy");36 Utils.trace ("Ast destroy");
41#if DEBUG
42 Utils.trace (" symbol count before destroy %d", leaked_symbols.size);
43#endif
44 // destroy the root symbol37 // destroy the root symbol
45 _root = null;38 _root = null;
46 source_files = null;// source have to be destroyes after root symbol39 source_files = null;// source have to be destroyes after root symbol
47
48#if DEBUG
49 Utils.trace (" symbol count after destroy %d", leaked_symbols.size);
50 if (leaked_symbols.size > 0) {
51 this.dump_leaks ();
52 }
53#endif
54
55 Utils.trace ("Ast destroyed");40 Utils.trace ("Ast destroyed");
56 }41 }
5742
@@ -69,11 +54,11 @@
6954
70 public Vala.List<SourceFile> source_files { get; set; }55 public Vala.List<SourceFile> source_files { get; set; }
71 56
72 public Symbol? lookup (string fully_qualified_name, out Symbol? parent)57 public Symbol? lookup (string fully_qualified_name)
73 {58 {
74 Symbol result = null;59 Symbol result = null;
75 60
76 parent = _root;61 Symbol parent = _root;
77 if (_root.has_children) {62 if (_root.has_children) {
78 result = lookup_symbol (fully_qualified_name, _root, ref parent, CompareMode.EXACT);63 result = lookup_symbol (fully_qualified_name, _root, ref parent, CompareMode.EXACT);
79 }64 }
@@ -148,7 +133,6 @@
148 */133 */
149134
150 foreach (SourceFile file in source_files) {135 foreach (SourceFile file in source_files) {
151
152 if (file.filename == filename) {136 if (file.filename == filename) {
153 return file;137 return file;
154 }138 }
@@ -582,10 +566,11 @@
582 // search in using directives566 // search in using directives
583 if (source.has_using_directives) {567 if (source.has_using_directives) {
584 foreach (DataType u in source.using_directives) {568 foreach (DataType u in source.using_directives) {
585 Symbol parent;569
586 570
587 sym = lookup (u.type_name, out parent);571 sym = lookup (u.type_name);
588 if (sym != null) {572 if (sym != null) {
573 Symbol parent = sym.parent;
589 if (compare_symbol_names (sym.name, name, mode)) {574 if (compare_symbol_names (sym.name, name, mode)) {
590 // is a reference to a namespace575 // is a reference to a namespace
591 return sym;576 return sym;
@@ -606,7 +591,7 @@
606 public Symbol? get_symbol_for_source_and_position (SourceFile source, int line, int column)591 public Symbol? get_symbol_for_source_and_position (SourceFile source, int line, int column)
607 {592 {
608 Symbol result = null;593 Symbol result = null;
609 SourceReference result_sr = null;594 unowned SourceReference result_sr = null;
610 595
611 if (source.has_symbols) {596 if (source.has_symbols) {
612 // base 0597 // base 0
@@ -638,19 +623,5 @@
638 623
639 return result;624 return result;
640 }625 }
641
642#if DEBUG
643 private void dump_leaks ()
644 {
645 foreach (Symbol s in leaked_symbols) {
646 Utils.trace (" -- leaked symbol %s (%p), parent %s (%p), generic_parent %s (%p) childs %d, refcount %u",
647 s.fully_qualified_name, s,
648 s.parent == null ? "null" : s.parent.fully_qualified_name, s.parent,
649 s.generic_parent == null ? "null" : s.generic_parent.fully_qualified_name, s.generic_parent,
650 s.has_children ? s.children.size : 0,
651 s.ref_count);
652 }
653 }
654#endif
655 }626 }
656}627}
657628
=== modified file 'plugins/completion/afrodite-provider/afrodite/astdumper.vala'
--- plugins/completion/afrodite-provider/afrodite/astdumper.vala 2010-09-03 21:40:48 +0000
+++ plugins/completion/afrodite-provider/afrodite/astdumper.vala 2011-03-10 19:26:24 +0000
@@ -140,7 +140,7 @@
140 inc_pad ();140 inc_pad ();
141 print ("%slocal variables\n", pad);141 print ("%slocal variables\n", pad);
142 foreach (DataType local in symbol.local_variables) {142 foreach (DataType local in symbol.local_variables) {
143 var sr = local.source_reference;143 unowned SourceReference sr = local.source_reference;
144 print ("%s %s - [(%d - %d) %s]\n",144 print ("%s %s - [(%d - %d) %s]\n",
145 pad,145 pad,
146 Utils.unescape_xml_string (local.description),146 Utils.unescape_xml_string (local.description),
147147
=== modified file 'plugins/completion/afrodite-provider/afrodite/astmerger.vala'
--- plugins/completion/afrodite-provider/afrodite/astmerger.vala 2010-12-30 07:38:50 +0000
+++ plugins/completion/afrodite-provider/afrodite/astmerger.vala 2011-03-10 19:26:24 +0000
@@ -28,40 +28,135 @@
28 {28 {
29 Afrodite.Symbol _current = null;29 Afrodite.Symbol _current = null;
30 Afrodite.DataType _current_type = null;30 Afrodite.DataType _current_type = null;
31 Afrodite.SourceReference _current_sr = null;31 unowned Afrodite.SourceReference _current_sr = null;
32 Afrodite.SourceFile _source_file = null;32 Afrodite.SourceFile _source_file = null;
33 Afrodite.DataType _inferred_type = null;33 Afrodite.DataType _inferred_type = null;
34 Vala.Literal _last_literal = null;34 Vala.Literal _last_literal = null;
35 35
36 string _vala_symbol_fqn = null;36 string _vala_symbol_fqn = null;
37 bool _merge_glib = true;37 bool _merge_glib = true;
38 int _child_count = 0;38
39
40 private Afrodite.Ast _ast = null;39 private Afrodite.Ast _ast = null;
41 40
42 public AstMerger (Afrodite.Ast ast)41 public AstMerger (Afrodite.Ast ast)
43 {42 {
44 this._ast = ast;43 this._ast = ast;
45 }44 }
4645
47 public void merge_vala_context (Vala.SourceFile source, CodeContext context, bool merge_glib = false)46 public async void merge_vala_context (Vala.SourceFile source, CodeContext context, bool merge_glib = false)
48 {47 {
49 _merge_glib = merge_glib;48 _merge_glib = merge_glib;
50 _vala_symbol_fqn = null;49 _vala_symbol_fqn = null;
51 _current_type = null;50 _current_type = null;
52 _child_count = 0;
53 _current = _ast.root;51 _current = _ast.root;
54 assert (_ast.lookup_source_file (source.filename) == null);52 assert (_ast.lookup_source_file (source.filename) == null);
5553
56 //debug ("COMPLETING FILE %s", source.filename);54 //debug ("COMPLETING FILE %s", source.filename);
57 _source_file = _ast.add_source_file (source.filename);55 _source_file = _ast.add_source_file (source.filename);
58 foreach (UsingDirective u in source.current_using_directives) {56 foreach (UsingDirective u in source.current_using_directives) {
59 _source_file.add_using_directive (u.namespace_symbol.get_full_name ());57 _source_file.add_using_directive (u.namespace_symbol.to_string ());
60 }58 }
61 context.root.accept_children (this);59 yield visit_namespace_sliced (context.root);
62 }60 }
6361
64 public void remove_source_filename (string filename)62 public async void visit_namespace_sliced (Namespace ns)
63 {
64 var prev_vala_fqn = _vala_symbol_fqn;
65 var prev = _current;
66 unowned SourceReference prev_sr = _current_sr;
67
68 if (ns.name != null)
69 _current = visit_symbol (ns, out _current_sr);
70
71 foreach (Enum en in ns.get_enums ()) {
72 en.accept (this);
73 }
74
75 foreach (ErrorDomain edomain in ns.get_error_domains ()) {
76 edomain.accept (this);
77 }
78
79 foreach (Vala.Namespace n in ns.get_namespaces ()) {
80 yield visit_namespace_sliced (n);
81 }
82
83 foreach (Vala.Class cl in ns.get_classes ()) {
84 yield visit_class_sliced (cl);
85 }
86
87 foreach (Interface iface in ns.get_interfaces ()) {
88 yield visit_interface_sliced (iface);
89 }
90
91 foreach (Struct st in ns.get_structs ()) {
92 yield visit_struct_sliced (st);
93 }
94
95 foreach (Delegate d in ns.get_delegates ()) {
96 d.accept (this);
97 }
98
99 foreach (Constant c in ns.get_constants ()) {
100 c.accept (this);
101 }
102
103 foreach (Field f in ns.get_fields ()) {
104 f.accept (this);
105 }
106
107 foreach (Method m in ns.get_methods ()) {
108 m.accept (this);
109 }
110
111 _current = prev;
112 _current_sr = prev_sr;
113 _vala_symbol_fqn = prev_vala_fqn;
114 }
115
116 public async void visit_class_sliced (Class c)
117 {
118 visit_class (c);
119 }
120
121 public async void visit_struct_sliced (Struct st)
122 {
123 visit_struct (st);
124 }
125
126 public async void visit_interface_sliced (Interface iface)
127 {
128 visit_interface (iface);
129 }
130
131 public override void visit_class (Class c)
132 {
133 var prev_vala_fqn = _vala_symbol_fqn;
134 var prev = _current;
135 unowned SourceReference prev_sr = _current_sr;
136
137 _current = visit_symbol (c, out _current_sr);
138 _current.is_abstract = c.is_abstract;
139 c.accept_children (this);
140
141 _current = prev;
142 _current_sr = prev_sr;
143 _vala_symbol_fqn = prev_vala_fqn;
144 }
145
146 public override void visit_struct (Struct s)
147 {
148 var prev_vala_fqn = _vala_symbol_fqn;
149 var prev = _current;
150 unowned SourceReference prev_sr = _current_sr;
151
152 _current = visit_symbol (s, out _current_sr);
153 s.accept_children (this);
154 _current = prev;
155 _current_sr = prev_sr;
156 _vala_symbol_fqn = prev_vala_fqn;
157 }
158
159 public async void remove_source_filename (string filename)
65 {160 {
66 var source = _ast.lookup_source_file (filename);161 var source = _ast.lookup_source_file (filename);
67 assert (source != null);162 assert (source != null);
@@ -69,65 +164,62 @@
69 _ast.remove_source (source);164 _ast.remove_source (source);
70 }165 }
71166
72 private Afrodite.Symbol visit_symbol (Vala.Symbol s, out Afrodite.SourceReference source_reference)167 private Afrodite.Symbol visit_symbol (Vala.Symbol s, out unowned Afrodite.SourceReference source_reference)
73 {168 {
74 Afrodite.Symbol symbol;169 Afrodite.Symbol symbol;
75170
76 set_fqn (s.name);171 set_fqn (s.name);
77 //symbol = _ast.lookup (_vala_symbol_fqn, out parent);
78 //assert (parent != null);
79 symbol = _ast.symbols.@get (_vala_symbol_fqn);
80172
81 if (symbol == null) {173 //NOTE: usually we should always add symbols but
174 // we should merge namespaces content.
175 // This must be changed whenever vala will support
176 // partial classes.
177 if (s.type_name != "ValaNamespace") {
82 symbol = add_symbol (s, out source_reference);178 symbol = add_symbol (s, out source_reference);
83 //Utils.trace ("adding %s to source %s", symbol.fully_qualified_name, _source_file.filename);
84 _current.add_child (symbol);179 _current.add_child (symbol);
85 } else {180 } else {
86 Afrodite.Symbol parent = symbol.parent;181 symbol = _ast.lookup (_vala_symbol_fqn);
87 //NOTE: see if we should replace the symbol182 if (symbol == null) {
88 // we should replace it if is not a namespace
89 // this can change whenever vala will support
90 // partial classes
91 bool replace = s.type_name != "ValaNamespace";
92 if (replace) {
93 parent.remove_child (symbol);
94 symbol = add_symbol (s, out source_reference);183 symbol = add_symbol (s, out source_reference);
95 parent.add_child (symbol);184 //Utils.trace ("adding %s to source %s", symbol.fully_qualified_name, _source_file.filename);
185 _current.add_child (symbol);
96 } else {186 } else {
187 source_reference = symbol.lookup_source_reference_filename (_source_file.filename);
97 // add one more source reference to the symbol188 // add one more source reference to the symbol
98 source_reference = symbol.lookup_source_reference_filename (_source_file.filename);
99 if (source_reference == null) {189 if (source_reference == null) {
100 source_reference = create_source_reference (s);190 var sr = create_source_reference (s);
101 symbol.add_source_reference (source_reference);191 symbol.add_source_reference (sr);
192 source_reference = sr;
102 //Utils.trace ("adding source reference %s to source %s", symbol.fully_qualified_name, _source_file.filename);193 //Utils.trace ("adding source reference %s to source %s", symbol.fully_qualified_name, _source_file.filename);
103 _source_file.add_symbol (symbol);194 _source_file.add_symbol (symbol);
104 } else {195 } else {
105 warning ("two sources with the same name were merged: %s", _source_file.filename);196 warning ("two sources with the same name were merged %s: %s", symbol.fully_qualified_name, _source_file.filename);
106 }197 }
107 }198 }
108 }199 }
109
110 return symbol;200 return symbol;
111 }201 }
112 202
113 private Afrodite.Symbol add_symbol (Vala.Symbol s, out Afrodite.SourceReference source_ref, int last_line = 0, int last_column = 0)203 private Afrodite.Symbol add_symbol (Vala.Symbol s, out unowned Afrodite.SourceReference source_ref, int last_line = 0, int last_column = 0)
114 {204 {
115 var symbol = new Afrodite.Symbol (_vala_symbol_fqn, s.type_name);205 var symbol = new Afrodite.Symbol (_vala_symbol_fqn, s.type_name);
116 if (symbol.lookup_source_reference_filename (_source_file.filename) == null) {206 if (symbol.lookup_source_reference_filename (_source_file.filename) == null) {
117 source_ref = create_source_reference (s, last_line, last_column);207 var sr = create_source_reference (s, last_line, last_column);
118 symbol.add_source_reference (source_ref);208 symbol.add_source_reference (sr);
209 source_ref = sr;
119 }210 }
120 symbol.access = get_vala_symbol_access (s.access);211 symbol.access = get_vala_symbol_access (s.access);
121 _source_file.add_symbol (symbol);212 _source_file.add_symbol (symbol);
122 return symbol;213 return symbol;
123 }214 }
124215
125 private Afrodite.Symbol add_codenode (string type_name, Vala.CodeNode c, out Afrodite.SourceReference source_ref, int last_line = 0, int last_column = 0)216 private Afrodite.Symbol add_codenode (string type_name, Vala.CodeNode c, out unowned Afrodite.SourceReference source_ref, int last_line = 0, int last_column = 0)
126 {217 {
127 var symbol = new Afrodite.Symbol (_vala_symbol_fqn, type_name);218 var symbol = new Afrodite.Symbol (_vala_symbol_fqn, type_name);
128 if (symbol.lookup_source_reference_filename (_source_file.filename) == null) {219 if (symbol.lookup_source_reference_filename (_source_file.filename) == null) {
129 source_ref = create_source_reference (c, last_line, last_column);220 var sr = create_source_reference (c, last_line, last_column);
130 symbol.add_source_reference (source_ref);221 symbol.add_source_reference (sr);
222 source_ref = sr;
131 }223 }
132 symbol.access = Afrodite.SymbolAccessibility.PRIVATE;224 symbol.access = Afrodite.SymbolAccessibility.PRIVATE;
133 _source_file.add_symbol (symbol);225 _source_file.add_symbol (symbol);
@@ -198,58 +290,11 @@
198 }290 }
199 }291 }
200292
201 public override void visit_namespace (Namespace ns)
202 {
203 var prev_vala_fqn = _vala_symbol_fqn;
204 var prev = _current;
205 var prev_sr = _current_sr;
206 var prev_child_count = _child_count;
207
208 _current = visit_symbol (ns, out _current_sr);
209 ns.accept_children (this);
210
211 _child_count = prev_child_count;
212 _current = prev;
213 _current_sr = prev_sr;
214 _vala_symbol_fqn = prev_vala_fqn;
215 }
216
217 public override void visit_class (Class c)
218 {
219 _child_count++;
220 var prev_vala_fqn = _vala_symbol_fqn;
221 var prev = _current;
222 var prev_sr = _current_sr;
223
224 _current = visit_symbol (c, out _current_sr);
225 _current.is_abstract = c.is_abstract;
226 c.accept_children (this);
227
228 _current = prev;
229 _current_sr = prev_sr;
230 _vala_symbol_fqn = prev_vala_fqn;
231 }
232
233 public override void visit_struct (Struct s)
234 {
235 _child_count++;
236 var prev_vala_fqn = _vala_symbol_fqn;
237 var prev = _current;
238 var prev_sr = _current_sr;
239
240 _current = visit_symbol (s, out _current_sr);
241 s.accept_children (this);
242 _current = prev;
243 _current_sr = prev_sr;
244 _vala_symbol_fqn = prev_vala_fqn;
245 }
246
247 public override void visit_interface (Interface iface)293 public override void visit_interface (Interface iface)
248 {294 {
249 _child_count++;
250 var prev_vala_fqn = _vala_symbol_fqn;295 var prev_vala_fqn = _vala_symbol_fqn;
251 var prev = _current;296 var prev = _current;
252 var prev_sr = _current_sr;297 unowned SourceReference prev_sr = _current_sr;
253298
254 _current = visit_symbol (iface, out _current_sr);299 _current = visit_symbol (iface, out _current_sr);
255 iface.accept_children (this);300 iface.accept_children (this);
@@ -258,6 +303,7 @@
258 _vala_symbol_fqn = prev_vala_fqn;303 _vala_symbol_fqn = prev_vala_fqn;
259 }304 }
260 305
306 /*
261 public override void visit_expression_statement (Vala.ExpressionStatement e)307 public override void visit_expression_statement (Vala.ExpressionStatement e)
262 {308 {
263 e.accept_children (this);309 e.accept_children (this);
@@ -268,13 +314,17 @@
268 //Utils.trace ("visit method call: %s", c.call.type_name);314 //Utils.trace ("visit method call: %s", c.call.type_name);
269 c.accept_children (this);315 c.accept_children (this);
270 }316 }
317 */
271 318
272 public override void visit_method (Method m)319 public override void visit_method (Method m)
273 {320 {
274 _child_count++;321 //var timer = new Timer();
322 //timer.start ();
323 //Utils.trace ("visit method %s", m.name);
324
275 var prev_vala_fqn = _vala_symbol_fqn;325 var prev_vala_fqn = _vala_symbol_fqn;
276 var prev = _current;326 var prev = _current;
277 var prev_sr = _current_sr;327 unowned SourceReference prev_sr = _current_sr;
278 328
279 set_fqn (m.name);329 set_fqn (m.name);
280 int last_line = 0;330 int last_line = 0;
@@ -301,18 +351,30 @@
301 351
302 _current = s;352 _current = s;
303 visit_type_for_generics (m.return_type, s.return_type);353 visit_type_for_generics (m.return_type, s.return_type);
304 m.accept_children (this);354 //Utils.trace ("visit method (symbol) %s: %f", m.name, timer.elapsed());
305 355 foreach (TypeParameter p in m.get_type_parameters ()) {
356 p.accept (this);
357 }
358 //Utils.trace ("visit method (typeparam) %s: %f", m.name, timer.elapsed());
359 foreach (Vala.Parameter param in m.get_parameters ()) {
360 param.accept (this);
361 }
362 //Utils.trace ("visit method (param) %s: %f", m.name, timer.elapsed());
363 if (m.body != null) {
364 m.body.accept (this);
365 }
366 //Utils.trace ("visit method (body) %s: %f", m.name, timer.elapsed());
306 _current = prev;367 _current = prev;
307 _current_sr = prev_sr;368 _current_sr = prev_sr;
308 _vala_symbol_fqn = prev_vala_fqn;369 _vala_symbol_fqn = prev_vala_fqn;
370 //Utils.trace ("visit method %s: %f", m.name, timer.elapsed());
309 }371 }
310372
311 public override void visit_creation_method (CreationMethod m)373 public override void visit_creation_method (CreationMethod m)
312 {374 {
313 var prev_vala_fqn = _vala_symbol_fqn;375 var prev_vala_fqn = _vala_symbol_fqn;
314 var prev = _current;376 var prev = _current;
315 var prev_sr = _current_sr;377 unowned SourceReference prev_sr = _current_sr;
316378
317 set_fqn (m.name);379 set_fqn (m.name);
318 int last_line = 0;380 int last_line = 0;
@@ -339,8 +401,18 @@
339 401
340 _current = s;402 _current = s;
341 visit_type_for_generics (m.return_type, s.return_type);403 visit_type_for_generics (m.return_type, s.return_type);
342 m.accept_children (this);404 foreach (TypeParameter p in m.get_type_parameters ()) {
343 405 p.accept (this);
406 }
407
408 foreach (Vala.Parameter param in m.get_parameters ()) {
409 param.accept (this);
410 }
411
412 if (m.body != null) {
413 m.body.accept (this);
414 }
415
344 _current = prev;416 _current = prev;
345 _current_sr = prev_sr;417 _current_sr = prev_sr;
346 _vala_symbol_fqn = prev_vala_fqn;418 _vala_symbol_fqn = prev_vala_fqn;
@@ -350,7 +422,7 @@
350 {422 {
351 var prev_vala_fqn = _vala_symbol_fqn;423 var prev_vala_fqn = _vala_symbol_fqn;
352 var prev = _current;424 var prev = _current;
353 var prev_sr = _current_sr;425 unowned SourceReference prev_sr = _current_sr;
354 426
355 set_fqn ("constructor:%s".printf(_current.fully_qualified_name));427 set_fqn ("constructor:%s".printf(_current.fully_qualified_name));
356 int last_line = 0;428 int last_line = 0;
@@ -363,8 +435,9 @@
363 _current.add_child (s);435 _current.add_child (s);
364 436
365 _current = s;437 _current = s;
366 m.accept_children (this);438 if (m.body != null) {
367 439 m.body.accept (this);
440 }
368 _current = prev;441 _current = prev;
369 _current_sr = prev_sr;442 _current_sr = prev_sr;
370 _vala_symbol_fqn = prev_vala_fqn;443 _vala_symbol_fqn = prev_vala_fqn;
@@ -374,7 +447,7 @@
374 {447 {
375 var prev_vala_fqn = _vala_symbol_fqn;448 var prev_vala_fqn = _vala_symbol_fqn;
376 var prev = _current;449 var prev = _current;
377 var prev_sr = _current_sr;450 unowned SourceReference prev_sr = _current_sr;
378 451
379 set_fqn ("destructor:%s".printf(_current.fully_qualified_name));452 set_fqn ("destructor:%s".printf(_current.fully_qualified_name));
380 int last_line = 0;453 int last_line = 0;
@@ -387,7 +460,10 @@
387 _current.add_child (s);460 _current.add_child (s);
388 461
389 _current = s;462 _current = s;
390 m.accept_children (this);463 if (m.body != null) {
464 m.body.accept (this);
465 }
466
391 _current = prev;467 _current = prev;
392 _current_sr = prev_sr;468 _current_sr = prev_sr;
393 _vala_symbol_fqn = prev_vala_fqn;469 _vala_symbol_fqn = prev_vala_fqn;
@@ -397,7 +473,7 @@
397 {473 {
398 var prev_vala_fqn = _vala_symbol_fqn;474 var prev_vala_fqn = _vala_symbol_fqn;
399 var prev = _current;475 var prev = _current;
400 var prev_sr = _current_sr;476 unowned SourceReference prev_sr = _current_sr;
401 477
402 set_fqn (ev.name);478 set_fqn (ev.name);
403 var sym = add_symbol (ev, out _current_sr);479 var sym = add_symbol (ev, out _current_sr);
@@ -412,16 +488,27 @@
412 488
413 public override void visit_enum (Vala.Enum e) 489 public override void visit_enum (Vala.Enum e)
414 {490 {
415 _child_count++;
416 var prev_vala_fqn = _vala_symbol_fqn;491 var prev_vala_fqn = _vala_symbol_fqn;
417 var prev = _current;492 var prev = _current;
418 var prev_sr = _current_sr;493 unowned SourceReference prev_sr = _current_sr;
419 494
420 set_fqn (e.name);495 set_fqn (e.name);
421 var s = add_symbol (e, out _current_sr);496 var s = add_symbol (e, out _current_sr);
422 _current.add_child (s);497 _current.add_child (s);
423 _current = s;498 _current = s;
424 e.accept_children (this);499
500 foreach (Vala.EnumValue value in e.get_values ()) {
501 value.accept (this);
502 }
503
504 foreach (Method m in e.get_methods ()) {
505 m.accept (this);
506 }
507
508 foreach (Constant c in e.get_constants ()) {
509 c.accept (this);
510 }
511
425 _current = prev;512 _current = prev;
426 _current_sr = prev_sr;513 _current_sr = prev_sr;
427 _vala_symbol_fqn = prev_vala_fqn;514 _vala_symbol_fqn = prev_vala_fqn;
@@ -429,16 +516,23 @@
429 516
430 public override void visit_delegate (Delegate d) 517 public override void visit_delegate (Delegate d)
431 {518 {
432 _child_count++;
433 var prev_vala_fqn = _vala_symbol_fqn;519 var prev_vala_fqn = _vala_symbol_fqn;
434 var prev = _current;520 var prev = _current;
435 var prev_sr = _current_sr;521 unowned SourceReference prev_sr = _current_sr;
436 522
437 set_fqn (d.name);523 set_fqn (d.name);
438 var sym = add_symbol (d, out _current_sr);524 var sym = add_symbol (d, out _current_sr);
525 sym.return_type = new DataType (d.return_type.to_string ());
439 _current.add_child (sym);526 _current.add_child (sym);
440 _current = sym;527 _current = sym;
441 d.accept_children (this);528
529 foreach (TypeParameter p in d.get_type_parameters ()) {
530 p.accept (this);
531 }
532 foreach (Vala.Parameter param in d.get_parameters ()) {
533 param.accept (this);
534 }
535
442 _current = prev;536 _current = prev;
443 _current_sr = prev_sr;537 _current_sr = prev_sr;
444 _vala_symbol_fqn = prev_vala_fqn;538 _vala_symbol_fqn = prev_vala_fqn;
@@ -446,10 +540,9 @@
446540
447 public override void visit_signal (Vala.Signal s) 541 public override void visit_signal (Vala.Signal s)
448 {542 {
449 _child_count++;
450 var prev_vala_fqn = _vala_symbol_fqn;543 var prev_vala_fqn = _vala_symbol_fqn;
451 var prev = _current;544 var prev = _current;
452 var prev_sr = _current_sr;545 unowned SourceReference prev_sr = _current_sr;
453 546
454 set_fqn (s.name);547 set_fqn (s.name);
455 var sym = add_symbol (s, out _current_sr);548 var sym = add_symbol (s, out _current_sr);
@@ -457,7 +550,16 @@
457 sym.is_virtual = s.is_virtual;550 sym.is_virtual = s.is_virtual;
458 _current.add_child (sym);551 _current.add_child (sym);
459 _current = sym;552 _current = sym;
460 s.accept_children (this);553
554 foreach (Vala.Parameter param in s.get_parameters ()) {
555 param.accept (this);
556 }
557 if (s.default_handler == null && s.body != null) {
558 s.body.accept (this);
559 } else if (s.default_handler != null) {
560 s.default_handler.accept (this);
561 }
562
461 _current = prev;563 _current = prev;
462 _current_sr = prev_sr;564 _current_sr = prev_sr;
463 _vala_symbol_fqn = prev_vala_fqn;565 _vala_symbol_fqn = prev_vala_fqn;
@@ -465,10 +567,9 @@
465 567
466 public override void visit_field (Field f) 568 public override void visit_field (Field f)
467 {569 {
468 _child_count++;
469 var prev_vala_fqn = _vala_symbol_fqn;570 var prev_vala_fqn = _vala_symbol_fqn;
470 var prev = _current;571 var prev = _current;
471 var prev_sr = _current_sr;572 unowned SourceReference prev_sr = _current_sr;
472 573
473 574
474 set_fqn (f.name);575 set_fqn (f.name);
@@ -494,10 +595,9 @@
494595
495 public override void visit_constant (Vala.Constant c) 596 public override void visit_constant (Vala.Constant c)
496 {597 {
497 _child_count++;
498 var prev_vala_fqn = _vala_symbol_fqn;598 var prev_vala_fqn = _vala_symbol_fqn;
499 var prev = _current;599 var prev = _current;
500 var prev_sr = _current_sr;600 unowned SourceReference prev_sr = _current_sr;
501 601
502 set_fqn (c.name);602 set_fqn (c.name);
503 var s = add_symbol (c, out _current_sr);603 var s = add_symbol (c, out _current_sr);
@@ -512,10 +612,9 @@
512 612
513 public override void visit_property (Property p) 613 public override void visit_property (Property p)
514 {614 {
515 _child_count++;
516 var prev_vala_fqn = _vala_symbol_fqn;615 var prev_vala_fqn = _vala_symbol_fqn;
517 var prev = _current;616 var prev = _current;
518 var prev_sr = _current_sr;617 unowned SourceReference prev_sr = _current_sr;
519 618
520 set_fqn (p.name);619 set_fqn (p.name);
521 var s = add_symbol (p, out _current_sr);620 var s = add_symbol (p, out _current_sr);
@@ -533,7 +632,17 @@
533 _current.add_child (s);632 _current.add_child (s);
534 633
535 _current = s;634 _current = s;
536 p.accept_children (this);635 if (p.get_accessor != null) {
636 p.get_accessor.accept (this);
637 }
638 if (p.set_accessor != null) {
639 p.set_accessor.accept (this);
640 }
641
642 if (p.initializer != null) {
643 p.initializer.accept (this);
644 }
645
537 _current = prev;646 _current = prev;
538 _current_sr = prev_sr;647 _current_sr = prev_sr;
539 _vala_symbol_fqn = prev_vala_fqn;648 _vala_symbol_fqn = prev_vala_fqn;
@@ -544,7 +653,7 @@
544 this.visit_scoped_codenode (a.readable ? "get" : "set", a, a.body);653 this.visit_scoped_codenode (a.readable ? "get" : "set", a, a.body);
545 /*654 /*
546 var prev = _current;655 var prev = _current;
547 var prev_sr = _current_sr;656 unowned SourceReference prev_sr = _current_sr;
548 657
549 if (a.body != null 658 if (a.body != null
550 && a.body.source_reference != null659 && a.body.source_reference != null
@@ -559,17 +668,23 @@
559 668
560 public override void visit_error_domain (ErrorDomain ed)669 public override void visit_error_domain (ErrorDomain ed)
561 {670 {
562 _child_count++;
563 var prev_vala_fqn = _vala_symbol_fqn;671 var prev_vala_fqn = _vala_symbol_fqn;
564 var prev = _current;672 var prev = _current;
565 var prev_sr = _current_sr;673 unowned SourceReference prev_sr = _current_sr;
566 674
567 set_fqn (ed.name);675 set_fqn (ed.name);
568 var s = add_symbol (ed, out _current_sr);676 var s = add_symbol (ed, out _current_sr);
569 _current.add_child (s);677 _current.add_child (s);
570 678
571 _current = s;679 _current = s;
572 ed.accept_children (this);680
681 foreach (ErrorCode ecode in ed.get_codes()) {
682 ecode.accept (this);
683 }
684 foreach (Method m in ed.get_methods ()) {
685 m.accept (this);
686 }
687
573 688
574 _current = prev;689 _current = prev;
575 _current_sr = prev_sr;690 _current_sr = prev_sr;
@@ -580,7 +695,7 @@
580 {695 {
581 var prev_vala_fqn = _vala_symbol_fqn;696 var prev_vala_fqn = _vala_symbol_fqn;
582 var prev = _current;697 var prev = _current;
583 var prev_sr = _current_sr;698 unowned SourceReference prev_sr = _current_sr;
584 699
585 set_fqn (ecode.name);700 set_fqn (ecode.name);
586 var s = add_symbol (ecode, out _current_sr);701 var s = add_symbol (ecode, out _current_sr);
@@ -649,17 +764,14 @@
649 {764 {
650 var prev_vala_fqn = _vala_symbol_fqn;765 var prev_vala_fqn = _vala_symbol_fqn;
651 var prev = _current;766 var prev = _current;
652 767
653 set_fqn (local.name);768 set_fqn (local.name);
654 DataType s = new DataType ("", local.name);769 DataType s = new DataType ("", local.name);
655 if (local.variable_type != null) {770 if (local.variable_type != null) {
656 s.type_name = get_datatype_typename (local.variable_type);771 s.type_name = get_datatype_typename (local.variable_type);
657 } else if (local.variable_type == null && local.initializer != null) {772 } else if (local.variable_type == null) {
658 // try to resolve local variable type from initializers
659 var prev_inferred_type = _inferred_type;
660 _inferred_type = s;
661 //Utils.trace ("infer from init '%s': %s", s.name, local.initializer.type_name);773 //Utils.trace ("infer from init '%s': %s", s.name, local.initializer.type_name);
662 774 /*
663 if (local.initializer is ObjectCreationExpression) {775 if (local.initializer is ObjectCreationExpression) {
664 //debug ("START: initialization %s from %s: %s", local.name, s.name, _inferred_type.type_name);776 //debug ("START: initialization %s from %s: %s", local.name, s.name, _inferred_type.type_name);
665 var obj_initializer = (ObjectCreationExpression) local.initializer;777 var obj_initializer = (ObjectCreationExpression) local.initializer;
@@ -667,12 +779,22 @@
667 //debug ("END: initialization done %s", _inferred_type.type_name);779 //debug ("END: initialization done %s", _inferred_type.type_name);
668 } else if (local.initializer is MethodCall) {780 } else if (local.initializer is MethodCall) {
669 //Utils.trace ("method call: %s", s.name);781 //Utils.trace ("method call: %s", s.name);
670 ((MethodCall) local.initializer).call.accept (this); // this avoid visit parameters of method calls782 var call = ((MethodCall) local.initializer);
783 Utils.trace ("method call: %s -> %s %s", local.name, call.to_string (), call.call.type_name);
784 var ma = call.call as MemberAccess;
785 if (true || ma == null)
786 call.call.accept (this); // this avoid visit parameters of method calls
787 else {
788
789 Utils.trace ("ma inner: %s", ma.member_name);
790 }
791 Utils.trace ("AFTER: %s", s.type_name);
792 //breakpoint();
671 } else if (local.initializer is BinaryExpression) {793 } else if (local.initializer is BinaryExpression) {
672 ((BinaryExpression) local.initializer).accept_children (this);794 ((BinaryExpression) local.initializer).accept_children (this);
673 } else if (local.initializer is CastExpression) {795 } else if (local.initializer is CastExpression) {
674 var cast_expr = (CastExpression)local.initializer;796 var cast_expr = (CastExpression)local.initializer;
675 cast_expr.accept (this);797 //cast_expr.accept (this);
676 if (cast_expr.type_reference != null)798 if (cast_expr.type_reference != null)
677 {799 {
678 s.type_name = get_datatype_typename (cast_expr.type_reference);800 s.type_name = get_datatype_typename (cast_expr.type_reference);
@@ -680,13 +802,34 @@
680 } else if (local.initializer is ArrayCreationExpression) {802 } else if (local.initializer is ArrayCreationExpression) {
681 //Utils.trace ("ArrayCreationExpression infer from init '%s' %s", s.name, local.initializer.type_name);803 //Utils.trace ("ArrayCreationExpression infer from init '%s' %s", s.name, local.initializer.type_name);
682 var ac = (ArrayCreationExpression) local.initializer; 804 var ac = (ArrayCreationExpression) local.initializer;
683 ac.accept_children (this);
684 s.is_array = true;805 s.is_array = true;
806 if (ac.element_type == null) {
807 if (ac.initializer_list != null) {
808 ac.initializer_list.accept (this);
809 }
810 }
685 s.type_name = get_datatype_typename (ac.element_type);811 s.type_name = get_datatype_typename (ac.element_type);
686 //Utils.trace ("init type %s: %s %s", local.name, s.type_name, ac.element_type.type_name);812 //Utils.trace ("init type %s: %s %s", local.name, s.type_name, ac.element_type.type_name);
687 } else {813 } else {
688 local.accept_children (this);814 if (local.initializer != null) {
689 }815 local.initializer.accept (this);
816 }
817 }
818 */
819 // try to resolve local variable type from initializers
820 var prev_inferred_type = _inferred_type;
821 _inferred_type = s;
822
823 if (local.initializer != null) {
824 local.initializer.accept (this);
825 // HACK:
826 if (s.type_name != null
827 && (s.type_name.has_prefix ("this.") || s.type_name.has_prefix ("base.")))
828 {
829 s.type_name = s.type_name.substring (5);
830 }
831 }
832
690 _last_literal = null;833 _last_literal = null;
691 //debug ("infer from init done %s", _inferred_type.type_name);834 //debug ("infer from init done %s", _inferred_type.type_name);
692 _inferred_type = prev_inferred_type;835 _inferred_type = prev_inferred_type;
@@ -734,23 +877,34 @@
734 {877 {
735 if (_inferred_type == null)878 if (_inferred_type == null)
736 return;879 return;
737 880
738 //Utils.trace ("visit member access %s: %s", _inferred_type.type_name, expr.member_name);881 string member_name = expr.member_name;
739 if (_inferred_type.type_name == null || _inferred_type.type_name == "")882 //Utils.trace ("MemberAccess %s: %s", _current.name, expr.member_name);
740 _inferred_type.type_name = expr.member_name;883 if (expr.inner == null) {
741 else {884 // this is the last iteration
742 string member_name = null;885 // lookup the name in all the visible symbols
743 // lookup in the scope variables
744 if (_current != null) {886 if (_current != null) {
745 DataType d = _current.scope_lookup_datatype_for_variable (CompareMode.EXACT, expr.member_name);887 // try the first optimized path
888 DataType d = _current.lookup_datatype_for_variable_name (CompareMode.EXACT, member_name);
746 if (d != null) {889 if (d != null) {
747 member_name = d.type_name;890 member_name = d.type_name;
891 } else if (_current.parent != null) {
892 d = _current.parent.lookup_datatype_for_symbol_name (CompareMode.EXACT, member_name);
893 if (d != null) {
894 member_name = d.type_name;
895 } /* else {
896 // this is the slowest path
897 d = _current.scope_lookup_datatype_for_name (CompareMode.EXACT, member_name);
898 if (d != null) {
899 member_name = d.type_name;
900 }
901 }*/
748 }902 }
749 }903 }
750 904 }
751 // if not found assume that is a static type905 if (_inferred_type.type_name == null || _inferred_type.type_name == "") {
752 if (member_name == null)906 _inferred_type.type_name = member_name;
753 member_name = expr.member_name;907 } else {
754 _inferred_type.type_name = "%s.%s".printf (member_name, _inferred_type.type_name);908 _inferred_type.type_name = "%s.%s".printf (member_name, _inferred_type.type_name);
755 }909 }
756 }910 }
@@ -777,7 +931,6 @@
777 931
778 public override void visit_binary_expression (BinaryExpression expr) 932 public override void visit_binary_expression (BinaryExpression expr)
779 {933 {
780 //debug ("vidit binary expr %p", expr);
781 expr.accept_children (this);934 expr.accept_children (this);
782 }935 }
783 936
@@ -788,8 +941,6 @@
788 941
789 if (_inferred_type.type_name == null || _inferred_type.type_name == "")942 if (_inferred_type.type_name == null || _inferred_type.type_name == "")
790 _inferred_type.type_name = "bool";943 _inferred_type.type_name = "bool";
791 else if (_inferred_type.type_name != "bool")
792 _inferred_type.type_name = "%s.%s".printf ("bool", _inferred_type.type_name);
793 }944 }
794945
795946
@@ -800,8 +951,6 @@
800 951
801 if (_inferred_type.type_name == null || _inferred_type.type_name == "")952 if (_inferred_type.type_name == null || _inferred_type.type_name == "")
802 _inferred_type.type_name = "char";953 _inferred_type.type_name = "char";
803 else if (_inferred_type.type_name != "char")
804 _inferred_type.type_name = "%s.%s".printf ("char", _inferred_type.type_name);
805 }954 }
806955
807 public override void visit_integer_literal (IntegerLiteral lit) 956 public override void visit_integer_literal (IntegerLiteral lit)
@@ -811,8 +960,6 @@
811960
812 if (_inferred_type.type_name == null || _inferred_type.type_name == "")961 if (_inferred_type.type_name == null || _inferred_type.type_name == "")
813 _inferred_type.type_name = lit.type_name;962 _inferred_type.type_name = lit.type_name;
814 else if (_inferred_type.type_name != lit.type_name)
815 _inferred_type.type_name = "%s.%s".printf (lit.type_name, _inferred_type.type_name);
816 }963 }
817964
818 public override void visit_real_literal (RealLiteral lit) 965 public override void visit_real_literal (RealLiteral lit)
@@ -821,8 +968,6 @@
821 return;968 return;
822 if (_inferred_type.type_name == null || _inferred_type.type_name == "")969 if (_inferred_type.type_name == null || _inferred_type.type_name == "")
823 _inferred_type.type_name = lit.get_type_name ();970 _inferred_type.type_name = lit.get_type_name ();
824 else if (_inferred_type.type_name != lit.get_type_name ())
825 _inferred_type.type_name = "%s.%s".printf (lit.get_type_name (), _inferred_type.type_name);
826 }971 }
827972
828 public override void visit_string_literal (StringLiteral lit) 973 public override void visit_string_literal (StringLiteral lit)
@@ -832,8 +977,6 @@
832 977
833 if (_inferred_type.type_name == null || _inferred_type.type_name == "")978 if (_inferred_type.type_name == null || _inferred_type.type_name == "")
834 _inferred_type.type_name = "string";979 _inferred_type.type_name = "string";
835 else if (_inferred_type.type_name != "string")
836 _inferred_type.type_name = "%s.%s".printf ("string", _inferred_type.type_name);
837 }980 }
838 981
839 public override void visit_declaration_statement (DeclarationStatement stmt)982 public override void visit_declaration_statement (DeclarationStatement stmt)
@@ -885,7 +1028,7 @@
885 {1028 {
886 var s = visit_scoped_codenode ("catch", clause, clause.body);1029 var s = visit_scoped_codenode ("catch", clause, clause.body);
887 var d = new DataType (get_datatype_typename (clause.error_type), clause.variable_name);1030 var d = new DataType (get_datatype_typename (clause.error_type), clause.variable_name);
888 s.add_local_variable (d); 1031 s.add_local_variable (d);
889 }1032 }
890 1033
891 public override void visit_if_statement (IfStatement stmt) 1034 public override void visit_if_statement (IfStatement stmt)
@@ -965,7 +1108,7 @@
965 {1108 {
966 var prev_vala_fqn = _vala_symbol_fqn;1109 var prev_vala_fqn = _vala_symbol_fqn;
967 var prev = _current;1110 var prev = _current;
968 var prev_sr = _current_sr;1111 unowned SourceReference prev_sr = _current_sr;
969 1112
970 set_fqn ("!%s".printf (name));1113 set_fqn ("!%s".printf (name));
971 int last_line = 0;1114 int last_line = 0;
9721115
=== modified file 'plugins/completion/afrodite-provider/afrodite/completionengine.vala'
--- plugins/completion/afrodite-provider/afrodite/completionengine.vala 2010-12-30 07:38:50 +0000
+++ plugins/completion/afrodite-provider/afrodite/completionengine.vala 2011-03-10 19:26:24 +0000
@@ -37,16 +37,16 @@
37 37
38 private Mutex _source_queue_mutex;38 private Mutex _source_queue_mutex;
39 private Mutex _merge_queue_mutex;39 private Mutex _merge_queue_mutex;
40 private Mutex _ast_mutex = null;
41 40
42 private unowned Thread<int> _parser_thread;41 private unowned Thread<int> _parser_thread;
43 private int _parser_stamp = 0;42 private int _parser_stamp = 0;
44 private int _parser_remaining_files = 0;43 private int _parser_remaining_files = 0;
45 private int _current_parsing_total_file_count = 0;44 private int _current_parsing_total_file_count = 0;
46 private bool _glib_init = false;45 private bool _glib_init = false;
47 46 private bool _is_parsing = false;
47
48 private Ast _ast;48 private Ast _ast;
49 private Vala.HashMap<string, ParseResult> _parse_result_list = new Vala.HashMap<string, ParseResult> (GLib.str_hash, GLib.str_equal, GLib.direct_equal);49 private Vala.List<ParseResult> _parse_result_list = new Vala.ArrayList<ParseResult> ();
50 private uint _idle_id = 0;50 private uint _idle_id = 0;
5151
52 public CompletionEngine (string? id = null)52 public CompletionEngine (string? id = null)
@@ -62,16 +62,13 @@
62 _merge_queue_mutex = new Mutex ();62 _merge_queue_mutex = new Mutex ();
63 63
64 _ast = new Ast ();64 _ast = new Ast ();
65 _ast_mutex = new Mutex ();
66 }65 }
67 66
68 ~Completion ()67 ~Completion ()
69 {68 {
70 Utils.trace ("Completion %s destroy", id);69 Utils.trace ("Completion %s destroy", id);
71 // invalidate the ast so the parser thread will exit asap70 // invalidate the ast so the parser thread will exit asap
72 _ast_mutex.lock ();
73 _ast = null;71 _ast = null;
74 _ast_mutex.unlock ();
7572
76 if (AtomicInt.@get (ref _parser_stamp) != 0) {73 if (AtomicInt.@get (ref _parser_stamp) != 0) {
77 Utils.trace ("join the parser thread before exit");74 Utils.trace ("join the parser thread before exit");
@@ -88,7 +85,7 @@
88 public bool is_parsing85 public bool is_parsing
89 {86 {
90 get {87 get {
91 return AtomicInt.@get (ref _parser_stamp) != 0;88 return _is_parsing;
92 }89 }
93 }90 }
9491
@@ -121,8 +118,10 @@
121 return null;118 return null;
122 }119 }
123120
124 public void queue_sources (Vala.List<SourceItem> sources)121 public bool queue_sources (Vala.List<SourceItem> sources, bool no_update_check = false)
125 {122 {
123 bool result = false;
124
126 _source_queue_mutex.@lock ();125 _source_queue_mutex.@lock ();
127 if (!_glib_init) {126 if (!_glib_init) {
128 // merge standard base vapi (glib and gobject)127 // merge standard base vapi (glib and gobject)
@@ -144,22 +143,36 @@
144 }143 }
145 }144 }
146 foreach (SourceItem source in sources) {145 foreach (SourceItem source in sources) {
147 var item = source_queue_contains (source);146 bool skip_unchanged_file = false;
148 if (item == null || item.content != source.content) {147
149 /*148 // test if file is really changed but only if it's not a live buffer
150 if (source.content == null || source.content == "")149 if (no_update_check == false && source.content == null && _ast != null) {
151 Utils.trace ("%s: queued source %s. sources to parse %d", id, source.path, source_queue.size);150 var sf = _ast.lookup_source_file (source.path);
152 else151 if (sf != null && sf.update_last_modification_time ()) {
153 Utils.trace ("%s: queued live buffer %s. sources to parse %d", id, source.path, source_queue.size);152 Utils.trace ("engine %s: skip unchanged source %s", id, source.path);
154 */ 153 skip_unchanged_file = true;
155 if (item != null)154 }
156 _source_queue.remove (item);155 }
157156
158 _source_queue.add (source.copy ());157 if (!skip_unchanged_file)
159 } 158 {
160 else if (item.content == null && source.content != null) {159 var item = source_queue_contains (source);
161 item.content = source.content;160 if (item == null || item.content != source.content) {
162 //Utils.trace ("%s: updated live buffer %s. sources to parse %d", id, source.path, source_queue.size);161 /*
162 if (source.content == null || source.content == "")
163 Utils.trace ("%s: queued source %s. sources to parse %d", id, source.path, source_queue.size);
164 else
165 Utils.trace ("%s: queued live buffer %s. sources to parse %d", id, source.path, source_queue.size);
166 */
167 if (item != null)
168 _source_queue.remove (item);
169
170 _source_queue.add (source.copy ());
171 }
172 else if (item.content == null && source.content != null) {
173 item.content = source.content;
174 //Utils.trace ("%s: updated live buffer %s. sources to parse %d", id, source.path, source_queue.size);
175 }
163 }176 }
164 }177 }
165 _source_queue_mutex.@unlock ();178 _source_queue_mutex.@unlock ();
@@ -168,7 +181,9 @@
168 create_parser_thread ();181 create_parser_thread ();
169 } else {182 } else {
170 AtomicInt.inc (ref _parser_stamp);183 AtomicInt.inc (ref _parser_stamp);
171 } 184 }
185
186 return result;
172 }187 }
173 188
174 public void queue_sourcefile (string path, string? content = null, bool is_vapi = false, bool is_glib = false)189 public void queue_sourcefile (string path, string? content = null, bool is_vapi = false, bool is_glib = false)
@@ -193,52 +208,12 @@
193 208
194 queue_sources (sources);209 queue_sources (sources);
195 }210 }
196 211
197 public bool try_acquire_ast (out Ast ast, int retry_count = -1)212 public Ast ast
198 {213 {
199 bool res = false;214 get {
200 ast = null;215 return _ast;
201 bool first_run = true;216 }
202 int file_count = 0;
203 int retry = 0;
204
205 while (ast == null
206 && _ast_mutex != null
207 && (first_run || (file_count = AtomicInt.get (ref _current_parsing_total_file_count)) <= 2))
208 {
209 first_run = false;
210 res = _ast_mutex.@trylock ();
211 if (res) {
212 ast = _ast;
213 } else {
214 if (retry_count < 0 || retry < retry_count) {
215 retry++;
216 GLib.Thread.usleep (100 * 1000);
217 } else {
218 break;
219 }
220 }
221 }
222
223#if DEBUG
224 if (ast == null) {
225 //Utils.trace ("can't acquire lock: %d", file_count);
226 } else {
227 Utils.trace ("lock acquired: %d", file_count);
228 }
229#endif
230
231 return res;
232 }
233
234 public void release_ast (Ast ast)
235 {
236 if (_ast != ast) {
237 warning ("%s: release_ast requested for unknown ast instance", id);
238 return;
239 }
240
241 _ast_mutex.unlock ();
242 }217 }
243218
244 private void create_parser_thread ()219 private void create_parser_thread ()
@@ -257,26 +232,19 @@
257 {232 {
258#if DEBUG233#if DEBUG
259 GLib.Timer timer = new GLib.Timer ();234 GLib.Timer timer = new GLib.Timer ();
260 double start_parsing_time = 0;
261 double parsing_time = 0;
262 double start_time = 0;235 double start_time = 0;
263 timer.start ();236 timer.start ();
264#endif237#endif
265 Utils.trace ("engine %s: parser thread *** starting ***...", id);238 Utils.trace ("engine %s: parser thread *** starting ***...", id);
266 begin_parsing (this);239
267 Vala.List<SourceItem> sources = new ArrayList<SourceItem> ();240 Vala.List<SourceItem> sources = new ArrayList<SourceItem> ();
268241
269 while (true) {242 while (true) {
270#if DEBUG
271 start_parsing_time = timer.elapsed ();
272#endif
273 int stamp = AtomicInt.get (ref _parser_stamp);243 int stamp = AtomicInt.get (ref _parser_stamp);
274 // set the number of sources to process + 1, because the last one244 // set the number of sources to process
275 // will be decreased by the resolve part245 AtomicInt.set (ref _parser_remaining_files, _source_queue.size );
276 AtomicInt.set (ref _parser_remaining_files, _source_queue.size + 1);
277 // get the source to parse246 // get the source to parse
278 _source_queue_mutex.@lock ();247 _source_queue_mutex.@lock ();
279 int source_count = _source_queue.size;
280 foreach (SourceItem item in _source_queue) {248 foreach (SourceItem item in _source_queue) {
281 sources.add (item.copy ());249 sources.add (item.copy ());
282 }250 }
@@ -287,109 +255,28 @@
287 _source_queue.clear ();255 _source_queue.clear ();
288 _source_queue_mutex.@unlock ();256 _source_queue_mutex.@unlock ();
289257
290 AstMerger merger = null;
291 foreach (SourceItem source in sources) {258 foreach (SourceItem source in sources) {
292 bool skip_unchanged_file = false;259#if DEBUG
293260 Utils.trace ("engine %s: parsing source: %s", id, source.path);
294 // test if file is really changed but only if it's not a live buffer261 start_time = timer.elapsed ();
295 if (source.content == null) {262#endif
296 _ast_mutex.@lock ();263
297 if (_ast != null) {264 Parser p = new Parser.with_source (source);
298 var sf = _ast.lookup_source_file (source.path);265 var parse_results = p.parse ();
299 if (sf != null) {266 lock (_parse_result_list) {
300 if (sf.update_last_modification_time ()) {267 _parse_result_list.add (parse_results);
301 // no need to reparse the source since it isn't changed268 if (_idle_id == 0)
302 Utils.trace ("engine %s: source file parsing optimized out since it isn't changed: %s", id, source.path);269 //_idle_id = Idle.add (this.on_parse_results, Priority.LOW);
303 _ast_mutex.@unlock ();270 _idle_id = Timeout.add (250, this.on_parse_results, Priority.LOW);
304 skip_unchanged_file = true;271 }
305 }272#if DEBUG
306 }273 Utils.trace ("engine %s: parsing source: %s done %g", id, source.path, timer.elapsed () - start_time);
307 }274#endif
308 _ast_mutex.@unlock ();
309 }
310
311 if (!skip_unchanged_file) {
312#if DEBUG
313 Utils.trace ("engine %s: parsing source: %s", id, source.path);
314 start_time = timer.elapsed ();
315#endif
316
317 Parser p = new Parser.with_source (source);
318 var parse_results = p.parse ();
319 lock (_parse_result_list) {
320 _parse_result_list.set (source.path, parse_results);
321 if (_idle_id == 0)
322 _idle_id = Idle.add_full (Priority.LOW, on_parse_results);
323 }
324#if DEBUG
325 Utils.trace ("engine %s: parsing source: %s done %g", id, source.path, timer.elapsed () - start_time);
326#endif
327 source.context = p.context;
328 if (source.context == null)
329 critical ("source %s context == null, non thread safe access to source item", source.path);
330 else {
331 foreach (Vala.SourceFile s in source.context.get_source_files ()) {
332 if (s.filename == source.path) {
333 // do the real merge
334 _ast_mutex.@lock ();
335 if (_ast != null) {
336 bool source_exists = _ast.lookup_source_file (source.path) != null;
337
338 // if the ast is still valid: not null
339 // and not
340 // if I'm parsing just one source and there are errors and the source already exists in the ast: I'll keep the previous copy
341 // do the merge
342 if (!(source_count == 1 && source_exists && p.context.report.get_errors () > 0)) {
343 if (merger == null) {
344 // lazy init the merger, here I'm sure that _ast != null
345 merger = new AstMerger (_ast);
346 }
347 if (source_exists) {
348 merger.remove_source_filename (source.path);
349 }
350#if DEBUG
351 Utils.trace ("engine %s: merging source %s", id, source.path);
352 start_time = timer.elapsed ();
353#endif
354 merger.merge_vala_context (s, source.context, source.is_glib);
355#if DEBUG
356 Utils.trace ("engine %s: merging source %s done %g", id, source.path, timer.elapsed () - start_time);
357#endif
358 }
359 }
360 _ast_mutex.unlock ();
361
362 //timer.stop ();
363 //debug ("%s: merging context and file %s in %g", id, s.filename, timer.elapsed ());
364 break;
365 }
366 }
367 }
368 }
369 AtomicInt.add (ref _parser_remaining_files, -1);275 AtomicInt.add (ref _parser_remaining_files, -1);
370 }276 }
371#if DEBUG
372 parsing_time += (timer.elapsed () - start_parsing_time);
373#endif
374277
375 _ast_mutex.@lock ();
376 if (_ast != null) {
377#if DEBUG
378 //_ast.dump_symbols ();
379 Utils.trace ("engine %s: resolving ast", id);
380 start_time = timer.elapsed ();
381#endif
382 var resolver = new SymbolResolver ();
383 resolver.resolve (_ast);
384#if DEBUG
385 Utils.trace ("engine %s: resolving ast done %g", id, timer.elapsed () - start_time);
386#endif
387 }
388 AtomicInt.add (ref _parser_remaining_files, -1);
389 _ast_mutex.unlock ();
390
391 sources.clear ();278 sources.clear ();
392 279
393 //check for changes or exit request280 //check for changes or exit request
394 if (_ast == null || AtomicInt.compare_and_exchange (ref _parser_stamp, stamp, 0)) {281 if (_ast == null || AtomicInt.compare_and_exchange (ref _parser_stamp, stamp, 0)) {
395 break;282 break;
@@ -402,36 +289,152 @@
402289
403#if DEBUG290#if DEBUG
404 timer.stop ();291 timer.stop ();
405 Utils.trace ("engine %s: parser thread *** exiting *** (elapsed time parsing %g, resolving %g)...", id, parsing_time, timer.elapsed ());292 Utils.trace ("engine %s: parser thread *** exiting *** (elapsed time parsing %g)...", id, timer.elapsed());
406#endif293#endif
407 end_parsing (this);
408 return 0;294 return 0;
409 }295 }
410 296
297 private void on_begin_parsing ()
298 {
299 if (!_is_parsing) {
300 _is_parsing = true;
301 begin_parsing (this);
302 }
303 }
304
305 private void on_end_parsing ()
306 {
307 if (AtomicInt.@get (ref _current_parsing_total_file_count) == 0) {
308 _is_parsing = false;
309 end_parsing (this);
310 }
311 }
312
313
411 private bool on_parse_results ()314 private bool on_parse_results ()
412 {315 {
413 bool more_results = true;316 bool merge_scheduled = false;
414 string filename = null;
415 ParseResult result = null;
416317
417 lock (_parse_result_list) {318 lock (_parse_result_list) {
418 if (_parse_result_list.size > 0) {319 if (_parse_result_list.size > 0) {
419 foreach (string key in _parse_result_list.get_keys ()) {320 foreach (ParseResult key in _parse_result_list) {
420 result = _parse_result_list.get (key);321 if (!merge_scheduled) {
421 _parse_result_list.remove (key);322 merge_scheduled = true;
422 filename = key;323 merge_and_resolve.begin (key, this.on_merge_and_resolve_ended);
423 break; // one iteration324 _parse_result_list.remove (key);
325 break;
326 }
424 }327 }
425 }328 } else {
426 if (_parse_result_list.size == 0) {329 // Tell to the parser thread the a new Idle should be created
330 // for the merge process
427 _idle_id = 0;331 _idle_id = 0;
428 more_results = false;332 }
429 }333 }
430 }334
431 if (result != null) {335 if (merge_scheduled) {
432 this.file_parsed (this, filename, result);336 on_begin_parsing();
433 }337 } else {
434 return more_results;338 // this is the last run after the merge
339 on_end_parsing ();
340 }
341
342 return false;
343 }
344
345 private void on_merge_and_resolve_ended (GLib.Object? source, GLib.AsyncResult r)
346 {
347 merge_and_resolve.end (r);
348 //_idle_id = Idle.add (this.on_parse_results, Priority.LOW);
349 _idle_id = Timeout.add (250, this.on_parse_results, Priority.LOW);
350 }
351
352 private async ParseResult merge_and_resolve (ParseResult result)
353 {
354 Utils.trace ("engine %s: async merge and resolve: %s", id, result.source_path);
355 foreach (Vala.SourceFile s in result.context.get_source_files ()) {
356 if (s.filename == result.source_path) {
357 var ast_source = _ast.lookup_source_file (result.source_path);
358 bool source_exists = ast_source != null;
359 bool need_update = true;
360
361 // if I already parsed this source and this copy is a live gedit buffer
362 // and the parsing contains some error, I maintain the previous copy in the ast
363 if (!(source_exists && result.is_edited && result.errors.size > 0))
364 {
365 // if the source was already parsed and it's not opend in a edit window
366 if (source_exists && !result.is_edited) {
367 need_update = ast_source.update_last_modification_time();
368 }
369 // this is important!
370 // TODO: we shouldn't hold this reference lookup_source_file should return an unowned ref
371 ast_source = null;
372 if (need_update) {
373 yield perform_merge_and_resolve (s, result, source_exists);
374 this.file_parsed (this, result.source_path, result);
375 }
376 } else {
377 Utils.trace ("engine %s: source (live buffer) with errors mantaining the previous parsing: %s", id, result.source_path);
378 }
379 break; // found the file
380 }
381 }
382
383 return result;
384 }
385
386 private async void perform_merge_and_resolve (Vala.SourceFile s, ParseResult result, bool source_exists)
387 {
388 yield merge_vala_source (s, result, source_exists);
389 yield resolve_ast ();
390 }
391
392 private async void merge_vala_source (Vala.SourceFile s, ParseResult result, bool source_exists)
393 {
394#if DEBUG
395 GLib.Timer timer = new GLib.Timer ();
396 double start_time = 0, elapsed;
397 timer.start ();
398#endif
399 var merger = new AstMerger (_ast);
400 if (source_exists) {
401#if DEBUG
402 Utils.trace ("engine %s: removing source (%p) %s", id, result, result.source_path);
403 start_time = timer.elapsed ();
404#endif
405 yield merger.remove_source_filename (result.source_path);
406#if DEBUG
407 Utils.trace ("engine %s: removing source (%p) %s done %g", id, result, result.source_path, timer.elapsed () - start_time);
408#endif
409 }
410#if DEBUG
411 Utils.trace ("engine %s: merging source %s", id, result.source_path);
412 start_time = timer.elapsed ();
413#endif
414 yield merger.merge_vala_context (s, result.context, result.is_glib);
415 result.context = null; // let's free some memory
416 merger = null;
417#if DEBUG
418 elapsed = timer.elapsed () - start_time;
419 Utils.trace ("engine %s: merging source %s done %g %s", id, result.source_path, elapsed, elapsed > 0.7 ? " <== Warning" : "");
420#endif
421 }
422
423 private async void resolve_ast ()
424 {
425#if DEBUG
426 GLib.Timer timer = new GLib.Timer ();
427 double start_time = 0;
428 timer.start ();
429 //_ast.dump_symbols ();
430 Utils.trace ("engine %s: resolving ast", id);
431 start_time = timer.elapsed ();
432#endif
433 var resolver = new SymbolResolver ();
434 resolver.resolve (_ast);
435#if DEBUG
436 Utils.trace ("engine %s: resolving ast done %g", id, timer.elapsed () - start_time);
437#endif
435 }438 }
436 }439 }
437}440}
438441
=== modified file 'plugins/completion/afrodite-provider/afrodite/parser.vala'
--- plugins/completion/afrodite-provider/afrodite/parser.vala 2010-10-14 16:01:50 +0000
+++ plugins/completion/afrodite-provider/afrodite/parser.vala 2011-03-10 19:26:24 +0000
@@ -26,21 +26,15 @@
26{26{
27 public class Parser : GLib.Object27 public class Parser : GLib.Object
28 {28 {
29 public CodeContext context = null;29 private CodeContext context = null;
3030
31 public Parser (Vala.List<SourceItem> sources)31 private unowned SourceItem _source;
32 {32
33 context = new Vala.CodeContext();
34 foreach (SourceItem source in sources) {
35 add_source_item (source);
36 }
37
38 }
39
40 public Parser.with_source (SourceItem source_item)33 public Parser.with_source (SourceItem source_item)
41 {34 {
42 context = new Vala.CodeContext();35 context = new Vala.CodeContext();
43 add_source_item (source_item);36 add_source_item (source_item);
37 _source = source_item;
44 }38 }
4539
46 private void add_source_item (SourceItem source)40 private void add_source_item (SourceItem source)
@@ -99,6 +93,11 @@
99 parser.parse (context);93 parser.parse (context);
10094
101 CodeContext.pop ();95 CodeContext.pop ();
96
97 parse_result.source_path = _source.path;
98 parse_result.is_glib = _source.is_glib;
99 parse_result.is_edited = _source.content != null;
100 parse_result.context = context;
102 return parse_result;101 return parse_result;
103 }102 }
104 }103 }
105104
=== modified file 'plugins/completion/afrodite-provider/afrodite/parseresult.vala'
--- plugins/completion/afrodite-provider/afrodite/parseresult.vala 2010-10-14 16:01:50 +0000
+++ plugins/completion/afrodite-provider/afrodite/parseresult.vala 2011-03-10 19:26:24 +0000
@@ -30,6 +30,11 @@
30 public Vala.List<string> errors = new Vala.ArrayList<string> ();30 public Vala.List<string> errors = new Vala.ArrayList<string> ();
31 public Vala.List<string> notes = new Vala.ArrayList<string> ();31 public Vala.List<string> notes = new Vala.ArrayList<string> ();
3232
33 public string source_path = null;
34 public bool is_glib = false;
35 public Vala.CodeContext context = null;
36 public bool is_edited = false;
37
33 public override void warn (Vala.SourceReference? source, string message)38 public override void warn (Vala.SourceReference? source, string message)
34 {39 {
35 base.warn (source, message);40 base.warn (source, message);
3641
=== modified file 'plugins/completion/afrodite-provider/afrodite/sourcefile.vala'
--- plugins/completion/afrodite-provider/afrodite/sourcefile.vala 2010-10-14 16:01:50 +0000
+++ plugins/completion/afrodite-provider/afrodite/sourcefile.vala 2011-03-10 19:26:24 +0000
@@ -69,16 +69,10 @@
69 ~SourceFile ()69 ~SourceFile ()
70 {70 {
71 Utils.trace ("SourceFile destroying: %s", filename);71 Utils.trace ("SourceFile destroying: %s", filename);
72#if DEBUG
73 Utils.trace (" symbol count before destroy %d", parent.leaked_symbols.size);
74#endif
75 while (symbols != null && symbols.size > 0) {72 while (symbols != null && symbols.size > 0) {
76 var symbol = symbols.get (0);73 var symbol = symbols.get (0);
77 remove_symbol (symbol);74 remove_symbol (symbol);
78 }75 }
79#if DEBUG
80 Utils.trace (" symbol count after destroy %d", parent.leaked_symbols.size);
81#endif
82 Utils.trace ("SourceFile destroyed: %s", filename);76 Utils.trace ("SourceFile destroyed: %s", filename);
83 }77 }
8478
@@ -130,21 +124,11 @@
130 if (symbols == null) {124 if (symbols == null) {
131 symbols = new ArrayList<unowned Symbol> ();125 symbols = new ArrayList<unowned Symbol> ();
132 }126 }
133 assert (symbols.contains (symbol) == false);
134127
135 symbols.add (symbol);128 symbols.add (symbol);
136129
137
138 parent.symbols.set (symbol.fully_qualified_name, symbol);130 parent.symbols.set (symbol.fully_qualified_name, symbol);
139#if DEBUG131 parent.unresolved_symbols.add(symbol);
140 // debug
141 if (!parent.leaked_symbols.contains (symbol)) {
142 //parent.leaked_symbols.add (symbol);
143 symbol.weak_ref (this.on_symbol_destroy);
144 } else {
145 Utils.trace ("Symbol already added to the leak check: %s", symbol.fully_qualified_name);
146 }
147#endif
148 }132 }
149133
150 public void remove_symbol (Symbol symbol)134 public void remove_symbol (Symbol symbol)
@@ -157,6 +141,7 @@
157141
158 if (!symbol.has_source_references) {142 if (!symbol.has_source_references) {
159 parent.symbols.remove (symbol.fully_qualified_name);143 parent.symbols.remove (symbol.fully_qualified_name);
144 parent.unresolved_symbols.remove (symbol);
160 if (symbol.parent != null) {145 if (symbol.parent != null) {
161 if (symbol.is_generic_type_argument) {146 if (symbol.is_generic_type_argument) {
162 symbol.parent.remove_generic_type_argument (symbol);147 symbol.parent.remove_generic_type_argument (symbol);
@@ -177,13 +162,5 @@
177 return symbols != null;162 return symbols != null;
178 }163 }
179 }164 }
180
181#if DEBUG
182 private void on_symbol_destroy (Object obj)
183 {
184 parent.leaked_symbols.remove ((Symbol)obj);
185 //Utils.trace ("symbol destroyed (%p)", obj);
186 }
187#endif
188 }165 }
189}166}
190167
=== modified file 'plugins/completion/afrodite-provider/afrodite/sourcereference.vala'
--- plugins/completion/afrodite-provider/afrodite/sourcereference.vala 2010-10-14 16:01:50 +0000
+++ plugins/completion/afrodite-provider/afrodite/sourcereference.vala 2011-03-10 19:26:24 +0000
@@ -23,13 +23,13 @@
2323
24namespace Afrodite24namespace Afrodite
25{25{
26 public class SourceReference : Object26 public class SourceReference
27 {27 {
28 public unowned SourceFile file { get; set; }28 public unowned SourceFile file;
29 public int first_line { get; set; }29 public int first_line;
30 public int last_line { get; set; }30 public int last_line;
31 public int first_column { get; set; }31 public int first_column;
32 public int last_column { get; set; }32 public int last_column;
33 33
34 public bool contains_position (int line, int column)34 public bool contains_position (int line, int column)
35 {35 {
3636
=== modified file 'plugins/completion/afrodite-provider/afrodite/symbol.vala'
--- plugins/completion/afrodite-provider/afrodite/symbol.vala 2010-10-14 16:01:50 +0000
+++ plugins/completion/afrodite-provider/afrodite/symbol.vala 2011-03-10 19:26:24 +0000
@@ -24,7 +24,7 @@
2424
25namespace Afrodite25namespace Afrodite
26{ 26{
27 public class Symbol : Object27 public class Symbol
28 {28 {
29 public static VoidType VOID = new VoidType ();29 public static VoidType VOID = new VoidType ();
30 public static EllipsisType ELLIPSIS = new EllipsisType ();30 public static EllipsisType ELLIPSIS = new EllipsisType ();
@@ -346,7 +346,7 @@
346 return null;346 return null;
347 }347 }
348348
349 public DataType? lookup_datatype_for_variable (CompareMode mode, string name, SymbolAccessibility access = SymbolAccessibility.ANY)349 public DataType? lookup_datatype_for_variable_name (CompareMode mode, string name, SymbolAccessibility access = SymbolAccessibility.ANY)
350 {350 {
351 if (has_local_variables) {351 if (has_local_variables) {
352 foreach (DataType d in local_variables) {352 foreach (DataType d in local_variables) {
@@ -355,7 +355,7 @@
355 }355 }
356 }356 }
357 }357 }
358 358
359 // search in symbol parameters359 // search in symbol parameters
360 if (has_parameters) {360 if (has_parameters) {
361 foreach (DataType type in parameters) {361 foreach (DataType type in parameters) {
@@ -365,6 +365,11 @@
365 }365 }
366 }366 }
367 367
368 return null;
369 }
370
371 public DataType? lookup_datatype_for_symbol_name (CompareMode mode, string name, SymbolAccessibility access = SymbolAccessibility.ANY)
372 {
368 if (has_children) {373 if (has_children) {
369 foreach (Symbol s in this.children) {374 foreach (Symbol s in this.children) {
370 if ((s.access & access) != 0375 if ((s.access & access) != 0
@@ -377,7 +382,7 @@
377 if (has_base_types) {382 if (has_base_types) {
378 foreach (DataType d in this.base_types) {383 foreach (DataType d in this.base_types) {
379 if (d.symbol != null) {384 if (d.symbol != null) {
380 var r = d.symbol.lookup_datatype_for_variable (mode, name, 385 var r = d.symbol.lookup_datatype_for_symbol_name (mode, name,
381 SymbolAccessibility.INTERNAL | SymbolAccessibility.PROTECTED | SymbolAccessibility.PROTECTED);386 SymbolAccessibility.INTERNAL | SymbolAccessibility.PROTECTED | SymbolAccessibility.PROTECTED);
382 if (r != null) {387 if (r != null) {
383 return d;388 return d;
@@ -387,15 +392,24 @@
387 }392 }
388 return null;393 return null;
389 }394 }
395
396 public DataType? lookup_datatype_for_name (CompareMode mode, string name, SymbolAccessibility access = SymbolAccessibility.ANY)
397 {
398 var result = lookup_datatype_for_variable_name (mode, name, access);
399 if (result != null)
400 return result;
401
402 return lookup_datatype_for_symbol_name (mode, name, access);
403 }
390 404
391 public DataType? scope_lookup_datatype_for_variable (CompareMode mode, string name)405 public DataType? scope_lookup_datatype_for_name (CompareMode mode, string name)
392 {406 {
393 DataType result = lookup_datatype_for_variable (mode, name);407 DataType result = lookup_datatype_for_name (mode, name);
394 408
395 if (result == null) {409 if (result == null) {
396410
397 if (this.parent != null) {411 if (this.parent != null) {
398 result = this.parent.scope_lookup_datatype_for_variable (mode, name);412 result = this.parent.scope_lookup_datatype_for_name (mode, name);
399 }413 }
400 414
401 if (result == null) {415 if (result == null) {
@@ -405,7 +419,7 @@
405 if (s.file.has_using_directives) {419 if (s.file.has_using_directives) {
406 foreach (var u in s.file.using_directives) {420 foreach (var u in s.file.using_directives) {
407 if (!u.unresolved) {421 if (!u.unresolved) {
408 result = u.symbol.lookup_datatype_for_variable (mode, name, SymbolAccessibility.INTERNAL | SymbolAccessibility.PUBLIC);422 result = u.symbol.lookup_datatype_for_symbol_name (mode, name, SymbolAccessibility.INTERNAL | SymbolAccessibility.PUBLIC);
409 if (result != null) {423 if (result != null) {
410 break;424 break;
411 }425 }
@@ -522,7 +536,6 @@
522 generic_type_arguments = new ArrayList<Symbol> ();536 generic_type_arguments = new ArrayList<Symbol> ();
523 }537 }
524538
525 assert (generic_type_arguments.contains(sym) == false);
526 //debug ("added generic %s to %s", sym.name, this.fully_qualified_name);539 //debug ("added generic %s to %s", sym.name, this.fully_qualified_name);
527 //Utils.trace ("add generic type args symbol %s: %s", _fully_qualified_name, sym.fully_qualified_name);540 //Utils.trace ("add generic type args symbol %s: %s", _fully_qualified_name, sym.fully_qualified_name);
528 generic_type_arguments.add (sym);541 generic_type_arguments.add (sym);
@@ -623,16 +636,18 @@
623 }636 }
624 }637 }
625 638
626 public SourceReference? lookup_source_reference_filename (string filename)639 public unowned SourceReference? lookup_source_reference_filename (string filename)
627 {640 {
641 unowned SourceReference? result = null;
628 if (has_source_references) {642 if (has_source_references) {
629 foreach (SourceReference reference in source_references) {643 foreach (SourceReference reference in source_references) {
630 if (reference.file.filename == filename)644 if (reference.file.filename == filename)
631 return reference;645 result = reference;
646 break;
632 }647 }
633 }648 }
634 649
635 return null;650 return result;
636 }651 }
637 652
638 public SourceReference? lookup_source_reference_sourcefile (SourceFile source)653 public SourceReference? lookup_source_reference_sourcefile (SourceFile source)
@@ -1053,7 +1068,6 @@
1053 if (_specialized_symbols == null)1068 if (_specialized_symbols == null)
1054 _specialized_symbols = new Vala.ArrayList<Symbol> ();1069 _specialized_symbols = new Vala.ArrayList<Symbol> ();
10551070
1056 assert (_specialized_symbols.contains (item) == false);
1057 _specialized_symbols.add (item);1071 _specialized_symbols.add (item);
1058 item.generic_parent = this;1072 item.generic_parent = this;
1059 }1073 }
@@ -1061,7 +1075,6 @@
1061 public void remove_specialized_symbol (Symbol? item)1075 public void remove_specialized_symbol (Symbol? item)
1062 {1076 {
1063 assert (item != this);1077 assert (item != this);
1064 assert (_specialized_symbols.contains (item));
10651078
1066 _specialized_symbols.remove (item);1079 _specialized_symbols.remove (item);
1067 if (item.generic_parent == this)1080 if (item.generic_parent == this)
10681081
=== modified file 'plugins/completion/afrodite-provider/afrodite/symbolresolver.vala'
--- plugins/completion/afrodite-provider/afrodite/symbolresolver.vala 2010-10-14 16:01:50 +0000
+++ plugins/completion/afrodite-provider/afrodite/symbolresolver.vala 2011-03-10 19:26:24 +0000
@@ -44,13 +44,12 @@
4444
45 // first resolve the using directives45 // first resolve the using directives
46 if (_ast.has_source_files) {46 if (_ast.has_source_files) {
47 Symbol dummy;
48 foreach (SourceFile file in _ast.source_files) {47 foreach (SourceFile file in _ast.source_files) {
49 if (file.has_using_directives) {48 if (file.has_using_directives) {
50 foreach (DataType using_directive in file.using_directives) {49 foreach (DataType using_directive in file.using_directives) {
51 //50 //
52 if (using_directive.unresolved) {51 if (using_directive.unresolved) {
53 using_directive.symbol = _ast.lookup (using_directive.type_name, out dummy);52 using_directive.symbol = _ast.lookup (using_directive.type_name);
54 if (using_directive.unresolved)53 if (using_directive.unresolved)
55 message ("file %s - can't resolve using directive: %s", file.filename, using_directive.type_name);54 message ("file %s - can't resolve using directive: %s", file.filename, using_directive.type_name);
56 }55 }
@@ -59,8 +58,12 @@
59 }58 }
60 }59 }
6160
62 if (ast.root.has_children)61 if (ast.unresolved_symbols.size > 0) {
63 visit_symbols (ast.root.children);62 Afrodite.Utils.trace ("(symbol resolver): symbols to resolve %d", ast.unresolved_symbols.size);
63 visit_symbols (ast.unresolved_symbols);
64 Afrodite.Utils.trace ("(symbol resolver): unresolved symbol after resolve process %d", ast.unresolved_symbols.size);
65 }
66
64 }67 }
65 68
66 private Symbol? resolve_type (Symbol symbol, DataType type)69 private Symbol? resolve_type (Symbol symbol, DataType type)
@@ -303,7 +306,52 @@
303306
304 }307 }
305 }308 }
306 309
310 private bool visit_symbol (Symbol symbol)
311 {
312 //print_symbol (symbol);
313 bool resolved = true;
314
315 // resolving base types
316 if (symbol.has_base_types) {
317 foreach (DataType type in symbol.base_types) {
318 if (type.unresolved) {
319 type.symbol = resolve_type (symbol, type);
320 resolved &= !type.unresolved;
321 }
322 }
323 }
324 // resolving return type
325 if (symbol.return_type != null) {
326 if (symbol.return_type.unresolved) {
327 symbol.return_type.symbol = resolve_type (symbol, symbol.return_type);
328 resolved &= !symbol.return_type.unresolved;
329 }
330 }
331
332 // resolving symbol parameters
333 if (symbol.has_parameters) {
334 foreach (DataType type in symbol.parameters) {
335 if (type.unresolved) {
336 type.symbol = resolve_type (symbol, type);
337 resolved &= !type.unresolved;
338 }
339 }
340 }
341 // resolving local variables
342 if (symbol.has_local_variables) {
343 foreach (DataType type in symbol.local_variables) {
344 if (type.unresolved) {
345 resolve_symbol (symbol, type);
346 resolved &= !type.unresolved;
347 }
348 }
349 }
350
351 return resolved;
352 }
353
354 /*
307 private void visit_symbol (Symbol symbol)355 private void visit_symbol (Symbol symbol)
308 {356 {
309 //print_symbol (symbol);357 //print_symbol (symbol);
@@ -342,13 +390,20 @@
342 if (symbol.has_children) {390 if (symbol.has_children) {
343 visit_symbols (symbol.children);391 visit_symbols (symbol.children);
344 }392 }
345 }393 }*/
346394
347 private void visit_symbols (Vala.List<Afrodite.Symbol> symbols)395 private void visit_symbols (Vala.List<unowned Afrodite.Symbol> symbols)
348 {396 {
397 Vala.List<unowned Afrodite.Symbol> resolved = new Vala.ArrayList<unowned Afrodite.Symbol>();
398
349 foreach (Symbol symbol in symbols) {399 foreach (Symbol symbol in symbols) {
350 visit_symbol (symbol);400 if (visit_symbol (symbol)) {
401 resolved.add (symbol);
402 }
351 }403 }
404
405 foreach (Symbol symbol in resolved)
406 symbols.remove(symbol);
352 }407 }
353 }408 }
354}409}

Subscribers

People subscribed via source and target branches

to all changes: