1 /**
2  * This file is part of DCD, a development tool for the D programming language.
3  * Copyright (C) 2014 Brian Schott
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 module dsymbol.conversion.first;
20 
21 import containers.unrolledlist;
22 import dparse.ast;
23 import dparse.formatter;
24 import dparse.lexer;
25 import dsymbol.builtin.names;
26 import dsymbol.builtin.symbols;
27 import dsymbol.cache_entry;
28 import dsymbol.import_;
29 import dsymbol.modulecache;
30 import dsymbol.scope_;
31 import dsymbol.semantic;
32 import dsymbol.string_interning;
33 import dsymbol.symbol;
34 import dsymbol.type_lookup;
35 import std.algorithm.iteration : map;
36 import stdx.allocator;
37 import stdx.allocator.mallocator;
38 import std.experimental.logger;
39 import std.typecons;
40 
41 /**
42  * First Pass handles the following:
43  * $(UL
44  *     $(LI symbol name)
45  *     $(LI symbol location)
46  *     $(LI alias this locations)
47  *     $(LI base class names)
48  *     $(LI protection level)
49  *     $(LI symbol kind)
50  *     $(LI function call tip)
51  *     $(LI symbol file path)
52  * )
53  */
54 final class FirstPass : ASTVisitor
55 {
56 	/**
57 	 * Params:
58 	 *     mod = the module to visit
59 	 *     symbolFile = path to the file being converted
60 	 *     symbolAllocator = allocator used for the auto-complete symbols
61 	 *     semanticAllocator = allocator used for semantic symbols
62 	 *     includeParameterSymbols = include parameter symbols as children of
63 	 *         function decalarations and constructors
64 	 */
65 	this(const Module mod, istring symbolFile, IAllocator symbolAllocator,
66 		IAllocator semanticAllocator, bool includeParameterSymbols,
67 		ModuleCache* cache, CacheEntry* entry = null)
68 	in
69 	{
70 		assert(mod);
71 		assert(symbolAllocator);
72 		assert(semanticAllocator);
73 		assert(cache);
74 	}
75 	body
76 	{
77 		this.mod = mod;
78 		this.symbolFile = symbolFile;
79 		this.symbolAllocator = symbolAllocator;
80 		this.semanticAllocator = semanticAllocator;
81 		this.includeParameterSymbols = includeParameterSymbols;
82 		this.entry = entry;
83 		this.cache = cache;
84 	}
85 
86 	/**
87 	 * Runs the against the AST and produces symbols.
88 	 */
89 	void run()
90 	{
91 		visit(mod);
92 	}
93 
94 	override void visit(const Unittest u)
95 	{
96 		// Create a dummy symbol because we don't want unit test symbols leaking
97 		// into the symbol they're declared in.
98 		pushSymbol(UNITTEST_SYMBOL_NAME,
99 			CompletionKind.dummy, istring(null));
100 		scope(exit) popSymbol();
101 		u.accept(this);
102 	}
103 
104 	override void visit(const Constructor con)
105 	{
106 		visitConstructor(con.location, con.parameters, con.templateParameters, con.functionBody, con.comment);
107 	}
108 
109 	override void visit(const SharedStaticConstructor con)
110 	{
111 		visitConstructor(con.location, null, null, con.functionBody, con.comment);
112 	}
113 
114 	override void visit(const StaticConstructor con)
115 	{
116 		visitConstructor(con.location, null, null, con.functionBody, con.comment);
117 	}
118 
119 	override void visit(const Destructor des)
120 	{
121 		visitDestructor(des.index, des.functionBody, des.comment);
122 	}
123 
124 	override void visit(const SharedStaticDestructor des)
125 	{
126 		visitDestructor(des.location, des.functionBody, des.comment);
127 	}
128 
129 	override void visit(const StaticDestructor des)
130 	{
131 		visitDestructor(des.location, des.functionBody, des.comment);
132 	}
133 
134 	override void visit(const FunctionDeclaration dec)
135 	{
136 		assert(dec);
137 		pushSymbol(dec.name.text, CompletionKind.functionName, symbolFile,
138 				dec.name.index, dec.returnType);
139 		scope (exit) popSymbol();
140 		currentSymbol.protection = protection.current;
141 		currentSymbol.acSymbol.doc = internString(dec.comment);
142 
143 		if (dec.functionBody !is null)
144 		{
145 			pushFunctionScope(dec.functionBody, semanticAllocator,
146 					dec.name.index + dec.name.text.length);
147 			scope (exit) popScope();
148 			processParameters(currentSymbol, dec.returnType,
149 					currentSymbol.acSymbol.name, dec.parameters, dec.templateParameters);
150 			dec.functionBody.accept(this);
151 		}
152 		else
153 		{
154 			immutable ips = includeParameterSymbols;
155 			includeParameterSymbols = false;
156 			processParameters(currentSymbol, dec.returnType,
157 					currentSymbol.acSymbol.name, dec.parameters, dec.templateParameters);
158 			includeParameterSymbols = ips;
159 		}
160 	}
161 
162 	override void visit(const ClassDeclaration dec)
163 	{
164 		visitAggregateDeclaration(dec, CompletionKind.className);
165 	}
166 
167 	override void visit(const TemplateDeclaration dec)
168 	{
169 		visitAggregateDeclaration(dec, CompletionKind.templateName);
170 	}
171 
172 	override void visit(const InterfaceDeclaration dec)
173 	{
174 		visitAggregateDeclaration(dec, CompletionKind.interfaceName);
175 	}
176 
177 	override void visit(const UnionDeclaration dec)
178 	{
179 		visitAggregateDeclaration(dec, CompletionKind.unionName);
180 	}
181 
182 	override void visit(const StructDeclaration dec)
183 	{
184 		visitAggregateDeclaration(dec, CompletionKind.structName);
185 	}
186 
187 	override void visit(const BaseClass bc)
188 	{
189 		if (bc.type2.typeIdentifierPart is null ||
190 			bc.type2.typeIdentifierPart.identifierOrTemplateInstance is null)
191 			return;
192 		auto lookup = Mallocator.instance.make!TypeLookup(TypeLookupKind.inherit);
193 		writeIotcTo(bc.type2.typeIdentifierPart, lookup.breadcrumbs);
194 		currentSymbol.typeLookups.insert(lookup);
195 	}
196 
197 	override void visit(const VariableDeclaration dec)
198 	{
199 		assert (currentSymbol);
200 		foreach (declarator; dec.declarators)
201 		{
202 			SemanticSymbol* symbol = allocateSemanticSymbol(
203 				declarator.name.text, CompletionKind.variableName,
204 				symbolFile, declarator.name.index);
205 			if (dec.type !is null)
206 				addTypeToLookups(symbol.typeLookups, dec.type);
207 			symbol.parent = currentSymbol;
208 			symbol.protection = protection.current;
209 			symbol.acSymbol.doc = internString(declarator.comment);
210 			currentSymbol.addChild(symbol, true);
211 			currentScope.addSymbol(symbol.acSymbol, false);
212 
213 			if (currentSymbol.acSymbol.kind == CompletionKind.structName
214 				|| currentSymbol.acSymbol.kind == CompletionKind.unionName)
215 			{
216 				structFieldNames.insert(symbol.acSymbol.name);
217 				// TODO: remove this cast. See the note on structFieldTypes
218 				structFieldTypes.insert(cast() dec.type);
219 			}
220 		}
221 		if (dec.autoDeclaration !is null)
222 		{
223 			foreach (part; dec.autoDeclaration.parts)
224 			{
225 				SemanticSymbol* symbol = allocateSemanticSymbol(
226 					part.identifier.text, CompletionKind.variableName,
227 					symbolFile, part.identifier.index);
228 				symbol.parent = currentSymbol;
229 				populateInitializer(symbol, part.initializer);
230 				symbol.protection = protection.current;
231 				symbol.acSymbol.doc = internString(dec.comment);
232 				currentSymbol.addChild(symbol, true);
233 				currentScope.addSymbol(symbol.acSymbol, false);
234 
235 				if (currentSymbol.acSymbol.kind == CompletionKind.structName
236 					|| currentSymbol.acSymbol.kind == CompletionKind.unionName)
237 				{
238 					structFieldNames.insert(symbol.acSymbol.name);
239 					// TODO: remove this cast. See the note on structFieldTypes
240 					structFieldTypes.insert(null);
241 				}
242 			}
243 		}
244 	}
245 
246 	override void visit(const AliasDeclaration aliasDeclaration)
247 	{
248 		if (aliasDeclaration.initializers.length == 0)
249 		{
250 			foreach (name; aliasDeclaration.declaratorIdentifierList.identifiers)
251 			{
252 				SemanticSymbol* symbol = allocateSemanticSymbol(
253 					name.text, CompletionKind.aliasName, symbolFile, name.index);
254 				if (aliasDeclaration.type !is null)
255 					addTypeToLookups(symbol.typeLookups, aliasDeclaration.type);
256 				symbol.parent = currentSymbol;
257 				currentSymbol.addChild(symbol, true);
258 				currentScope.addSymbol(symbol.acSymbol, false);
259 				symbol.protection = protection.current;
260 				symbol.acSymbol.doc = internString(aliasDeclaration.comment);
261 			}
262 		}
263 		else
264 		{
265 			foreach (initializer; aliasDeclaration.initializers)
266 			{
267 				SemanticSymbol* symbol = allocateSemanticSymbol(
268 					initializer.name.text, CompletionKind.aliasName,
269 					symbolFile, initializer.name.index);
270 				if (initializer.type !is null)
271 					addTypeToLookups(symbol.typeLookups, initializer.type);
272 				symbol.parent = currentSymbol;
273 				currentSymbol.addChild(symbol, true);
274 				currentScope.addSymbol(symbol.acSymbol, false);
275 				symbol.protection = protection.current;
276 				symbol.acSymbol.doc = internString(aliasDeclaration.comment);
277 			}
278 		}
279 	}
280 
281 	override void visit(const AliasThisDeclaration dec)
282 	{
283 		currentSymbol.typeLookups.insert(Mallocator.instance.make!TypeLookup(
284 			internString(dec.identifier.text), TypeLookupKind.aliasThis));
285 	}
286 
287 	override void visit(const Declaration dec)
288 	{
289 		if (dec.attributeDeclaration !is null
290 			&& isProtection(dec.attributeDeclaration.attribute.attribute.type))
291 		{
292 			protection.addScope(dec.attributeDeclaration.attribute.attribute.type);
293 			return;
294 		}
295 		IdType p;
296 		foreach (const Attribute attr; dec.attributes)
297 		{
298 			if (isProtection(attr.attribute.type))
299 				p = attr.attribute.type;
300 		}
301 		if (p != tok!"")
302 		{
303 			protection.beginLocal(p);
304 			if (dec.declarations.length > 0)
305 			{
306 				protection.beginScope();
307 				dec.accept(this);
308 				protection.endScope();
309 			}
310 			else
311 				dec.accept(this);
312 			protection.endLocal();
313 		}
314 		else
315 			dec.accept(this);
316 	}
317 
318 	override void visit(const Module mod)
319 	{
320 		rootSymbol = allocateSemanticSymbol(null, CompletionKind.moduleName,
321 			symbolFile);
322 		currentSymbol = rootSymbol;
323 		moduleScope = semanticAllocator.make!Scope(0, uint.max);
324 		currentScope = moduleScope;
325 		auto objectLocation = cache.resolveImportLocation("object");
326 		if (objectLocation is null)
327 			warning("Could not locate object.d or object.di");
328 		else
329 		{
330 			auto objectImport = allocateSemanticSymbol(IMPORT_SYMBOL_NAME,
331 				CompletionKind.importSymbol, objectLocation);
332 			objectImport.acSymbol.skipOver = true;
333 			currentSymbol.addChild(objectImport, true);
334 			currentScope.addSymbol(objectImport.acSymbol, false);
335 		}
336 		foreach (s; builtinSymbols[])
337 			currentScope.addSymbol(s, false);
338 		mod.accept(this);
339 	}
340 
341 	override void visit(const EnumDeclaration dec)
342 	{
343 		assert (currentSymbol);
344 		SemanticSymbol* symbol = allocateSemanticSymbol(dec.name.text,
345 			CompletionKind.enumName, symbolFile, dec.name.index);
346 		if (dec.type !is null)
347 			addTypeToLookups(symbol.typeLookups, dec.type);
348 		symbol.acSymbol.addChildren(enumSymbols[], false);
349 		symbol.parent = currentSymbol;
350 		currentSymbol.addChild(symbol, true);
351 		currentScope.addSymbol(symbol.acSymbol, false);
352 		symbol.acSymbol.doc = internString(dec.comment);
353 		currentSymbol = symbol;
354 
355 		if (dec.enumBody !is null)
356 		{
357 			pushScope(dec.enumBody.startLocation, dec.enumBody.endLocation);
358 			dec.enumBody.accept(this);
359 			popScope();
360 		}
361 
362 		currentSymbol = currentSymbol.parent;
363 	}
364 
365 	mixin visitEnumMember!EnumMember;
366 	mixin visitEnumMember!AnonymousEnumMember;
367 
368 	override void visit(const ModuleDeclaration moduleDeclaration)
369 	{
370 		rootSymbol.acSymbol.name = internString(moduleDeclaration.moduleName.identifiers[$ - 1].text);
371 	}
372 
373 	override void visit(const StructBody structBody)
374 	{
375 		import std.algorithm : move;
376 
377 		pushScope(structBody.startLocation, structBody.endLocation);
378 		scope (exit) popScope();
379 		protection.beginScope();
380 		scope (exit) protection.endScope();
381 
382 		auto savedStructFieldNames = move(structFieldNames);
383 		auto savedStructFieldTypes = move(structFieldTypes);
384 		scope(exit) structFieldNames = move(savedStructFieldNames);
385 		scope(exit) structFieldTypes = move(savedStructFieldTypes);
386 
387 		DSymbol* thisSymbol = make!DSymbol(symbolAllocator, THIS_SYMBOL_NAME,
388 			CompletionKind.variableName, currentSymbol.acSymbol);
389 		thisSymbol.location = currentScope.startLocation;
390 		thisSymbol.symbolFile = symbolFile;
391 		thisSymbol.type = currentSymbol.acSymbol;
392 		thisSymbol.ownType = false;
393 		currentScope.addSymbol(thisSymbol, false);
394 
395 		foreach (dec; structBody.declarations)
396 			visit(dec);
397 
398 		// If no constructor is found, generate one
399 		if ((currentSymbol.acSymbol.kind == CompletionKind.structName
400 				|| currentSymbol.acSymbol.kind == CompletionKind.unionName)
401 				&& currentSymbol.acSymbol.getFirstPartNamed(CONSTRUCTOR_SYMBOL_NAME) is null)
402 			createConstructor();
403 	}
404 
405 	override void visit(const ImportDeclaration importDeclaration)
406 	{
407 		import std.algorithm : filter, map;
408 		import std.path : buildPath;
409 		import std.typecons : Tuple;
410 
411 		foreach (single; importDeclaration.singleImports.filter!(
412 			a => a !is null && a.identifierChain !is null))
413 		{
414 			immutable importPath = convertChainToImportPath(single.identifierChain);
415 			istring modulePath = cache.resolveImportLocation(importPath);
416 			if (modulePath is null)
417 			{
418 				warning("Could not resolve location of module '", importPath, "'");
419 				continue;
420 			}
421 			SemanticSymbol* importSymbol = allocateSemanticSymbol(IMPORT_SYMBOL_NAME,
422 				CompletionKind.importSymbol, modulePath);
423 			importSymbol.acSymbol.skipOver = protection.currentForImport != tok!"public";
424 			if (single.rename == tok!"")
425 			{
426 				size_t i = 0;
427 				DSymbol* currentImportSymbol;
428 				foreach (p; single.identifierChain.identifiers.map!(a => a.text))
429 				{
430 					immutable bool first = i == 0;
431 					immutable bool last = i + 1 >= single.identifierChain.identifiers.length;
432 					immutable CompletionKind kind = last ? CompletionKind.moduleName
433 						: CompletionKind.packageName;
434 					istring ip = internString(p);
435 					if (first)
436 					{
437 						auto s = currentScope.getSymbolsByName(ip);
438 						if (s.length == 0)
439 						{
440 							currentImportSymbol = symbolAllocator.make!DSymbol(ip, kind);
441 							currentScope.addSymbol(currentImportSymbol, true);
442 							if (last)
443 							{
444 								currentImportSymbol.symbolFile = modulePath;
445 								currentImportSymbol.type = importSymbol.acSymbol;
446 								currentImportSymbol.ownType = false;
447 							}
448 						}
449 						else
450 							currentImportSymbol = s[0];
451 					}
452 					else
453 					{
454 						auto s = currentImportSymbol.getPartsByName(ip);
455 						if (s.length == 0)
456 						{
457 							auto sym = symbolAllocator.make!DSymbol(ip, kind);
458 							currentImportSymbol.addChild(sym, true);
459 							currentImportSymbol = sym;
460 							if (last)
461 							{
462 								currentImportSymbol.symbolFile = modulePath;
463 								currentImportSymbol.type = importSymbol.acSymbol;
464 								currentImportSymbol.ownType = false;
465 							}
466 						}
467 						else
468 							currentImportSymbol = s[0];
469 					}
470 					i++;
471 				}
472 				currentSymbol.addChild(importSymbol, true);
473 				currentScope.addSymbol(importSymbol.acSymbol, false);
474 			}
475 			else
476 			{
477 				SemanticSymbol* renameSymbol = allocateSemanticSymbol(
478 					internString(single.rename.text), CompletionKind.aliasName,
479 					modulePath);
480 				renameSymbol.acSymbol.skipOver = protection.current != tok!"public";
481 				renameSymbol.acSymbol.type = importSymbol.acSymbol;
482 				renameSymbol.acSymbol.ownType = true;
483 				renameSymbol.addChild(importSymbol, true);
484 				currentSymbol.addChild(renameSymbol, true);
485 				currentScope.addSymbol(renameSymbol.acSymbol, false);
486 			}
487 			if (entry !is null)
488 				entry.dependencies.insert(modulePath);
489 		}
490 		if (importDeclaration.importBindings is null) return;
491 		if (importDeclaration.importBindings.singleImport.identifierChain is null) return;
492 
493 		immutable chain = convertChainToImportPath(importDeclaration.importBindings.singleImport.identifierChain);
494 		istring modulePath = cache.resolveImportLocation(chain);
495 		if (modulePath is null)
496 		{
497 			warning("Could not resolve location of module '", chain, "'");
498 			return;
499 		}
500 
501 		foreach (bind; importDeclaration.importBindings.importBinds)
502 		{
503 			TypeLookup* lookup = Mallocator.instance.make!TypeLookup(
504 				TypeLookupKind.selectiveImport);
505 
506 			immutable bool isRenamed = bind.right != tok!"";
507 
508 			// The second phase must change this `importSymbol` kind to
509 			// `aliasName` for symbol lookup to work.
510 			SemanticSymbol* importSymbol = allocateSemanticSymbol(
511 				isRenamed ? bind.left.text : IMPORT_SYMBOL_NAME,
512 				CompletionKind.importSymbol, modulePath);
513 
514 			if (isRenamed)
515 			{
516 				lookup.breadcrumbs.insert(internString(bind.right.text));
517 				importSymbol.acSymbol.location = bind.left.index;
518 				importSymbol.acSymbol.altFile = symbolFile;
519 			}
520 			lookup.breadcrumbs.insert(internString(bind.left.text));
521 
522 			importSymbol.acSymbol.qualifier = SymbolQualifier.selectiveImport;
523 			importSymbol.typeLookups.insert(lookup);
524 			importSymbol.acSymbol.skipOver = protection.current != tok!"public";
525 			currentSymbol.addChild(importSymbol, true);
526 			currentScope.addSymbol(importSymbol.acSymbol, false);
527 		}
528 
529 		if (entry !is null)
530 			entry.dependencies.insert(modulePath);
531 	}
532 
533 	// Create scope for block statements
534 	override void visit(const BlockStatement blockStatement)
535 	{
536 		if (blockStatement.declarationsAndStatements !is null)
537 		{
538 			pushScope(blockStatement.startLocation, blockStatement.endLocation);
539 			scope(exit) popScope();
540 			visit (blockStatement.declarationsAndStatements);
541 		}
542 	}
543 
544 	override void visit(const TemplateMixinExpression tme)
545 	{
546 		// TODO: support typeof here
547 		if (tme.mixinTemplateName.symbol is null)
548 			return;
549 		auto lookup = Mallocator.instance.make!TypeLookup(TypeLookupKind.mixinTemplate);
550 		writeIotcTo(tme.mixinTemplateName.symbol.identifierOrTemplateChain,
551 			lookup.breadcrumbs);
552 
553 		if (currentSymbol.acSymbol.kind != CompletionKind.functionName)
554 			currentSymbol.typeLookups.insert(lookup);
555 	}
556 
557 	override void visit(const ForeachStatement feStatement)
558 	{
559 		if (feStatement.declarationOrStatement !is null
560 			&& feStatement.declarationOrStatement.statement !is null
561 			&& feStatement.declarationOrStatement.statement.statementNoCaseNoDefault !is null
562 			&& feStatement.declarationOrStatement.statement.statementNoCaseNoDefault.blockStatement !is null)
563 		{
564 			const BlockStatement bs =
565 				feStatement.declarationOrStatement.statement.statementNoCaseNoDefault.blockStatement;
566 			pushScope(feStatement.startIndex, bs.endLocation);
567 			scope(exit) popScope();
568 			feExpression = feStatement.low.items[$ - 1];
569 			feStatement.accept(this);
570 			feExpression = null;
571 		}
572 		else
573 		{
574 			const ubyte o1 = foreachTypeIndexOfInterest;
575 			const ubyte o2 = foreachTypeIndex;
576 			feStatement.accept(this);
577 			foreachTypeIndexOfInterest = o1;
578 			foreachTypeIndex = o2;
579 		}
580 	}
581 
582 	override void visit(const ForeachTypeList feTypeList)
583 	{
584 		foreachTypeIndex = 0;
585 		foreachTypeIndexOfInterest = cast(ubyte)(feTypeList.items.length - 1);
586 		feTypeList.accept(this);
587 	}
588 
589 	override void visit(const ForeachType feType)
590 	{
591 		if (foreachTypeIndex++ == foreachTypeIndexOfInterest)
592 		{
593 		    SemanticSymbol* symbol = allocateSemanticSymbol(feType.identifier.text,
594 			    CompletionKind.variableName, symbolFile, feType.identifier.index);
595 		    if (feType.type !is null)
596 			    addTypeToLookups(symbol.typeLookups, feType.type);
597 		    symbol.parent = currentSymbol;
598 		    currentSymbol.addChild(symbol, true);
599 		    currentScope.addSymbol(symbol.acSymbol, true);
600 		    if (symbol.typeLookups.empty && feExpression !is null)
601 			    populateInitializer(symbol, feExpression, true);
602 		}
603 	}
604 
605 	override void visit(const WithStatement withStatement)
606 	{
607 		if (withStatement.expression !is null
608 			&& withStatement.statementNoCaseNoDefault !is null)
609 		{
610 			pushScope(withStatement.statementNoCaseNoDefault.startLocation,
611 				withStatement.statementNoCaseNoDefault.endLocation);
612 			scope(exit) popScope();
613 
614 			pushSymbol(WITH_SYMBOL_NAME, CompletionKind.withSymbol, symbolFile,
615 				currentScope.startLocation, null);
616 			scope(exit) popSymbol();
617 
618 			populateInitializer(currentSymbol, withStatement.expression, false);
619 			withStatement.accept(this);
620 
621 		}
622 		else
623 			withStatement.accept(this);
624 	}
625 
626 	alias visit = ASTVisitor.visit;
627 
628 	/// Module scope
629 	Scope* moduleScope;
630 
631 	/// The module
632 	SemanticSymbol* rootSymbol;
633 
634 	/// Allocator used for symbol allocation
635 	IAllocator symbolAllocator;
636 
637 	/// Number of symbols allocated
638 	uint symbolsAllocated;
639 
640 private:
641 
642 	void createConstructor()
643 	{
644 		import std.array : appender;
645 		import std.range : zip;
646 
647 		auto app = appender!(char[])();
648 		app.put("this(");
649 		bool first = true;
650 		foreach (field; zip(structFieldTypes[], structFieldNames[]))
651 		{
652 			if (first)
653 				first = false;
654 			else
655 				app.put(", ");
656 			if (field[0] is null)
657 				app.put("auto ");
658 			else
659 			{
660 				app.formatNode(field[0]);
661 				app.put(" ");
662 			}
663 			app.put(field[1]);
664 		}
665 		app.put(")");
666 		SemanticSymbol* symbol = allocateSemanticSymbol(CONSTRUCTOR_SYMBOL_NAME,
667 			CompletionKind.functionName, symbolFile, currentSymbol.acSymbol.location);
668 		symbol.acSymbol.callTip = internString(cast(string) app.data);
669 		currentSymbol.addChild(symbol, true);
670 	}
671 
672 	void pushScope(size_t startLocation, size_t endLocation)
673 	{
674 		assert (startLocation < uint.max);
675 		assert (endLocation < uint.max || endLocation == size_t.max);
676 		Scope* s = semanticAllocator.make!Scope(cast(uint) startLocation, cast(uint) endLocation);
677 		s.parent = currentScope;
678 		currentScope.children.insert(s);
679 		currentScope = s;
680 	}
681 
682 	void popScope()
683 	{
684 		currentScope = currentScope.parent;
685 	}
686 
687 	void pushFunctionScope(const FunctionBody functionBody,
688 		IAllocator semanticAllocator, size_t scopeBegin)
689 	{
690 		import std.algorithm : max;
691 
692 		immutable scopeEnd = max(
693 			functionBody.inStatement is null ? 0 : functionBody.inStatement.blockStatement.endLocation,
694 			functionBody.outStatement is null ? 0 : functionBody.outStatement.blockStatement.endLocation,
695 			functionBody.blockStatement is null ? 0 : functionBody.blockStatement.endLocation,
696 			functionBody.bodyStatement is null ? 0 : functionBody.bodyStatement.blockStatement.endLocation);
697 		Scope* s = semanticAllocator.make!Scope(cast(uint) scopeBegin, cast(uint) scopeEnd);
698 		s.parent = currentScope;
699 		currentScope.children.insert(s);
700 		currentScope = s;
701 	}
702 
703 	void pushSymbol(string name, CompletionKind kind, istring symbolFile,
704 		size_t location = 0, const Type type = null)
705 	{
706 		SemanticSymbol* symbol = allocateSemanticSymbol(name, kind, symbolFile,
707 			location);
708 		if (type !is null)
709 			addTypeToLookups(symbol.typeLookups, type);
710 		symbol.parent = currentSymbol;
711 		currentSymbol.addChild(symbol, true);
712 		currentScope.addSymbol(symbol.acSymbol, false);
713 		currentSymbol = symbol;
714 	}
715 
716 	void popSymbol()
717 	{
718 		currentSymbol = currentSymbol.parent;
719 	}
720 
721 	template visitEnumMember(T)
722 	{
723 		override void visit(const T member)
724 		{
725 			pushSymbol(member.name.text, CompletionKind.enumMember, symbolFile,
726 				member.name.index, member.type);
727 			scope(exit) popSymbol();
728 			currentSymbol.acSymbol.doc = internString(member.comment);
729 		}
730 	}
731 
732 	void visitAggregateDeclaration(AggType)(AggType dec, CompletionKind kind)
733 	{
734 		if (kind == CompletionKind.unionName && dec.name == tok!"")
735 		{
736 			dec.accept(this);
737 			return;
738 		}
739 		pushSymbol(dec.name.text, kind, symbolFile, dec.name.index);
740 		scope(exit) popSymbol();
741 
742 		if (kind == CompletionKind.className)
743 			currentSymbol.acSymbol.addChildren(classSymbols[], false);
744 		else
745 			currentSymbol.acSymbol.addChildren(aggregateSymbols[], false);
746 		currentSymbol.protection = protection.current;
747 		currentSymbol.acSymbol.doc = internString(dec.comment);
748 
749 		immutable size_t scopeBegin = dec.name.index + dec.name.text.length;
750 		static if (is (AggType == const(TemplateDeclaration)))
751 			immutable size_t scopeEnd = dec.endLocation;
752 		else
753 			immutable size_t scopeEnd = dec.structBody is null ? scopeBegin : dec.structBody.endLocation;
754 		pushScope(scopeBegin, scopeEnd);
755 		scope(exit) popScope();
756 		protection.beginScope();
757 		scope (exit) protection.endScope();
758 		processTemplateParameters(currentSymbol, dec.templateParameters);
759 		dec.accept(this);
760 	}
761 
762 	void visitConstructor(size_t location, const Parameters parameters,
763 		const TemplateParameters templateParameters,
764 		const FunctionBody functionBody, string doc)
765 	{
766 		SemanticSymbol* symbol = allocateSemanticSymbol(CONSTRUCTOR_SYMBOL_NAME,
767 			CompletionKind.functionName, symbolFile, location);
768 		symbol.parent = currentSymbol;
769 		currentSymbol.addChild(symbol, true);
770 		processParameters(symbol, null, THIS_SYMBOL_NAME, parameters, templateParameters);
771 		symbol.protection = protection.current;
772 		symbol.acSymbol.doc = internString(doc);
773 		if (functionBody !is null)
774 		{
775 			pushFunctionScope(functionBody, semanticAllocator,
776 				location + 4); // 4 == "this".length
777 			scope(exit) popScope();
778 			currentSymbol = symbol;
779 			functionBody.accept(this);
780 			currentSymbol = currentSymbol.parent;
781 		}
782 	}
783 
784 	void visitDestructor(size_t location, const FunctionBody functionBody, string doc)
785 	{
786 		SemanticSymbol* symbol = allocateSemanticSymbol(DESTRUCTOR_SYMBOL_NAME,
787 			CompletionKind.functionName, symbolFile, location);
788 		symbol.parent = currentSymbol;
789 		currentSymbol.addChild(symbol, true);
790 		symbol.acSymbol.callTip = internString("~this()");
791 		symbol.protection = protection.current;
792 		symbol.acSymbol.doc = internString(doc);
793 		if (functionBody !is null)
794 		{
795 			pushFunctionScope(functionBody, semanticAllocator, location + 4); // 4 == "this".length
796 			scope(exit) popScope();
797 			currentSymbol = symbol;
798 			functionBody.accept(this);
799 			currentSymbol = currentSymbol.parent;
800 		}
801 	}
802 
803 	void processParameters(SemanticSymbol* symbol, const Type returnType,
804 		string functionName, const Parameters parameters,
805 		const TemplateParameters templateParameters)
806 	{
807 		processTemplateParameters(symbol, templateParameters);
808 		if (includeParameterSymbols && parameters !is null)
809 		{
810 			foreach (const Parameter p; parameters.parameters)
811 			{
812 				SemanticSymbol* parameter = allocateSemanticSymbol(
813 					p.name.text, CompletionKind.variableName, symbolFile,
814 					p.name.index);
815 				if (p.type !is null)
816 					addTypeToLookups(parameter.typeLookups, p.type);
817 				parameter.parent = currentSymbol;
818 				currentSymbol.acSymbol.argNames.insert(parameter.acSymbol.name);
819 				currentSymbol.addChild(parameter, true);
820 				currentScope.addSymbol(parameter.acSymbol, false);
821 			}
822 			if (parameters.hasVarargs)
823 			{
824 				SemanticSymbol* argptr = allocateSemanticSymbol(ARGPTR_SYMBOL_NAME,
825 					CompletionKind.variableName, istring(null), size_t.max);
826 				addTypeToLookups(argptr.typeLookups, argptrType);
827 				argptr.parent = currentSymbol;
828 				currentSymbol.addChild(argptr, true);
829 				currentScope.addSymbol(argptr.acSymbol, false);
830 
831 				SemanticSymbol* arguments = allocateSemanticSymbol(
832 					ARGUMENTS_SYMBOL_NAME, CompletionKind.variableName,
833 					istring(null), size_t.max);
834 				addTypeToLookups(arguments.typeLookups, argumentsType);
835 				arguments.parent = currentSymbol;
836 				currentSymbol.addChild(arguments, true);
837 				currentScope.addSymbol(arguments.acSymbol, false);
838 			}
839 		}
840 		symbol.acSymbol.callTip = formatCallTip(returnType, functionName,
841 			parameters, templateParameters);
842 	}
843 
844 	void processTemplateParameters(SemanticSymbol* symbol, const TemplateParameters templateParameters)
845 	{
846 		if (includeParameterSymbols && templateParameters !is null
847 				&& templateParameters.templateParameterList !is null)
848 		{
849 			foreach (const TemplateParameter p; templateParameters.templateParameterList.items)
850 			{
851 				string name;
852 				CompletionKind kind;
853 				size_t index;
854 				Rebindable!(const(Type)) type;
855 				if (p.templateAliasParameter !is null)
856 				{
857 					name = p.templateAliasParameter.identifier.text;
858 					kind = CompletionKind.aliasName;
859 					index = p.templateAliasParameter.identifier.index;
860 				}
861 				else if (p.templateTypeParameter !is null)
862 				{
863 					name = p.templateTypeParameter.identifier.text;
864 					kind = CompletionKind.aliasName;
865 					index = p.templateTypeParameter.identifier.index;
866 				}
867 				else if (p.templateValueParameter !is null)
868 				{
869 					name = p.templateValueParameter.identifier.text;
870 					kind = CompletionKind.variableName;
871 					index = p.templateValueParameter.identifier.index;
872 					type = p.templateValueParameter.type;
873 				}
874 				else
875 					continue;
876 				SemanticSymbol* templateParameter = allocateSemanticSymbol(name,
877 					kind, symbolFile, index);
878 				if (type !is null)
879 					addTypeToLookups(templateParameter.typeLookups, type);
880 				templateParameter.parent = symbol;
881 				symbol.addChild(templateParameter, true);
882 			}
883 		}
884 	}
885 
886 	istring formatCallTip(const Type returnType, string name,
887 		const Parameters parameters, const TemplateParameters templateParameters)
888 	{
889 		import std.array : appender;
890 
891 		auto app = appender!(char[])();
892 		if (returnType !is null)
893 		{
894 			app.formatNode(returnType);
895 			app.put(' ');
896 		}
897 		app.put(name);
898 		if (templateParameters !is null)
899 			app.formatNode(templateParameters);
900 		if (parameters is null)
901 			app.put("()");
902 		else
903 			app.formatNode(parameters);
904 		return internString(cast(string) app.data);
905 	}
906 
907 	void populateInitializer(T)(SemanticSymbol* symbol, const T initializer,
908 		bool appendForeach = false)
909 	{
910 		auto lookup = Mallocator.instance.make!TypeLookup(TypeLookupKind.initializer);
911 		auto visitor = scoped!InitializerVisitor(lookup, appendForeach);
912 		symbol.typeLookups.insert(lookup);
913 		visitor.visit(initializer);
914 	}
915 
916 	SemanticSymbol* allocateSemanticSymbol(string name, CompletionKind kind,
917 		istring symbolFile, size_t location = 0)
918 	in
919 	{
920 		assert (symbolAllocator !is null);
921 	}
922 	body
923 	{
924 		DSymbol* acSymbol = make!DSymbol(symbolAllocator, name, kind);
925 		acSymbol.location = location;
926 		acSymbol.symbolFile = symbolFile;
927 		symbolsAllocated++;
928 		return semanticAllocator.make!SemanticSymbol(acSymbol);
929 	}
930 
931 	void addTypeToLookups(ref UnrolledList!(TypeLookup*, Mallocator, false) lookups,
932 		const Type type, TypeLookup* l = null)
933 	{
934 		auto lookup = l !is null ? l : Mallocator.instance.make!TypeLookup(
935 			TypeLookupKind.varOrFunType);
936 		auto t2 = type.type2;
937 		if (t2.type !is null)
938 			addTypeToLookups(lookups, t2.type, lookup);
939 		else if (t2.superOrThis is tok!"this")
940 			lookup.breadcrumbs.insert(internString("this"));
941 		else if (t2.superOrThis is tok!"super")
942 			lookup.breadcrumbs.insert(internString("super"));
943 		else if (t2.builtinType !is tok!"")
944 			lookup.breadcrumbs.insert(getBuiltinTypeName(t2.builtinType));
945 		else if (t2.typeIdentifierPart !is null)
946 			writeIotcTo(t2.typeIdentifierPart, lookup.breadcrumbs);
947 		else
948 		{
949 			// TODO: Add support for typeof expressions
950 			// TODO: Add support for __vector
951 //			warning("typeof() and __vector are not yet supported");
952 		}
953 
954 		foreach (suffix; type.typeSuffixes)
955 		{
956 			if (suffix.star != tok!"")
957 				continue;
958 			else if (suffix.type)
959 				lookup.breadcrumbs.insert(ASSOC_ARRAY_SYMBOL_NAME);
960 			else if (suffix.array)
961 				lookup.breadcrumbs.insert(ARRAY_SYMBOL_NAME);
962 			else if (suffix.star != tok!"")
963 				lookup.breadcrumbs.insert(POINTER_SYMBOL_NAME);
964 			else if (suffix.delegateOrFunction != tok!"")
965 			{
966 				import std.array : appender;
967 				auto app = appender!(char[])();
968 				formatNode(app, type);
969 				istring callTip = internString(cast(string) app.data);
970 				// Insert the call tip and THEN the "function" string because
971 				// the breadcrumbs are processed in reverse order
972 				lookup.breadcrumbs.insert(callTip);
973 				lookup.breadcrumbs.insert(FUNCTION_SYMBOL_NAME);
974 			}
975 		}
976 		if (l is null)
977 			lookups.insert(lookup);
978 	}
979 
980 	/// Current protection type
981 	ProtectionStack protection;
982 
983 	/// Current scope
984 	Scope* currentScope;
985 
986 	/// Current symbol
987 	SemanticSymbol* currentSymbol;
988 
989 	/// Path to the file being converted
990 	istring symbolFile;
991 
992 	/// Field types used for generating struct constructors if no constructor
993 	/// was defined
994 	// TODO: This should be `const Type`, but Rebindable and opEquals don't play
995 	// well together
996 	UnrolledList!(Type) structFieldTypes;
997 
998 	/// Field names for struct constructor generation
999 	UnrolledList!(istring) structFieldNames;
1000 
1001 	const Module mod;
1002 
1003 	IAllocator semanticAllocator;
1004 
1005 	Rebindable!(const ExpressionNode) feExpression;
1006 
1007 	CacheEntry* entry;
1008 
1009 	ModuleCache* cache;
1010 
1011 	bool includeParameterSymbols;
1012 
1013 	ubyte foreachTypeIndexOfInterest;
1014 	ubyte foreachTypeIndex;
1015 }
1016 
1017 struct ProtectionStack
1018 {
1019 	invariant
1020 	{
1021 		import std.algorithm.iteration : filter, joiner, map;
1022 		import std.conv:to;
1023 		import std.range : walkLength;
1024 
1025 		assert(stack.length == stack[].filter!(a => isProtection(a)
1026 				|| a == tok!":" || a == tok!"{").walkLength(), to!string(stack[].map!(a => str(a)).joiner(", ")));
1027 	}
1028 
1029 	IdType currentForImport() const
1030 	{
1031 		return stack.empty ? tok!"default" : current();
1032 	}
1033 
1034 	IdType current() const
1035 	{
1036 		import std.algorithm.iteration : filter;
1037 		import std.range : choose, only;
1038 
1039 		IdType retVal;
1040 		foreach (t; choose(stack.empty, only(tok!"public"), stack[]).filter!(
1041 				a => a != tok!"{" && a != tok!":"))
1042 			retVal = cast(IdType) t;
1043 		return retVal;
1044 	}
1045 
1046 	void beginScope()
1047 	{
1048 		stack.insertBack(tok!"{");
1049 	}
1050 
1051 	void endScope()
1052 	{
1053 		import std.algorithm.iteration : joiner;
1054 		import std.conv : to;
1055 		import std.range : walkLength;
1056 
1057 		while (!stack.empty && stack.back == tok!":")
1058 		{
1059 			assert(stack.length >= 2);
1060 			stack.popBack();
1061 			stack.popBack();
1062 		}
1063 		assert(stack.length == stack[].walkLength());
1064 		assert(!stack.empty && stack.back == tok!"{", to!string(stack[].map!(a => str(a)).joiner(", ")));
1065 		stack.popBack();
1066 	}
1067 
1068 	void beginLocal(const IdType t)
1069 	{
1070 		assert (t != tok!"", "DERP!");
1071 		stack.insertBack(t);
1072 	}
1073 
1074 	void endLocal()
1075 	{
1076 		import std.algorithm.iteration : joiner;
1077 		import std.conv : to;
1078 
1079 		assert(!stack.empty && stack.back != tok!":" && stack.back != tok!"{",
1080 				to!string(stack[].map!(a => str(a)).joiner(", ")));
1081 		stack.popBack();
1082 	}
1083 
1084 	void addScope(const IdType t)
1085 	{
1086 		assert(t != tok!"", "DERP!");
1087 		assert(isProtection(t));
1088 		if (!stack.empty && stack.back == tok!":")
1089 		{
1090 			assert(stack.length >= 2);
1091 			stack.popBack();
1092 			assert(isProtection(stack.back));
1093 			stack.popBack();
1094 		}
1095 		stack.insertBack(t);
1096 		stack.insertBack(tok!":");
1097 	}
1098 
1099 private:
1100 
1101 	UnrolledList!IdType stack;
1102 }
1103 
1104 void formatNode(A, T)(ref A appender, const T node)
1105 {
1106 	if (node is null)
1107 		return;
1108 	auto f = scoped!(Formatter!(A*))(&appender);
1109 	f.format(node);
1110 }
1111 
1112 private:
1113 
1114 auto byIdentifier(const TypeIdentifierPart tip) pure nothrow @trusted
1115 {
1116 	TypeIdentifierPart root = cast() tip;
1117 
1118 	struct Range
1119 	{
1120 		auto front() pure nothrow @nogc @safe
1121 		{
1122 			assert(root !is null);
1123 			assert(root.identifierOrTemplateInstance !is null);
1124 
1125 			with (root.identifierOrTemplateInstance)
1126 			return identifier != tok!""
1127 				? identifier.text
1128 				: templateInstance.identifier.text;
1129 		}
1130 
1131 		void popFront() pure nothrow @nogc @safe
1132 		{
1133 			assert(root !is null, "attempt to pop the front of an empty byIdentifier.Range");
1134 			root = cast() root.typeIdentifierPart;
1135 		}
1136 
1137 		bool empty() pure nothrow @nogc @safe
1138 		{
1139 			return root is null;
1140 		}
1141 	}
1142 
1143 	Range range;
1144 	return range;
1145 }
1146 
1147 void writeIotcTo(T)(const TypeIdentifierPart tip, ref T output) nothrow
1148 {
1149 	import std.algorithm : each;
1150 
1151 	byIdentifier(tip).each!(a => output.insert(internString(a)));
1152 }
1153 
1154 auto byIdentifier(const IdentifierOrTemplateChain iotc) nothrow
1155 {
1156 	import std.algorithm : map;
1157 
1158 	return iotc.identifiersOrTemplateInstances.map!(a => a.identifier == tok!""
1159 		? a.templateInstance.identifier.text
1160 		: a.identifier.text);
1161 }
1162 
1163 void writeIotcTo(T)(const IdentifierOrTemplateChain iotc, ref T output) nothrow
1164 {
1165 	import std.algorithm : each;
1166 
1167 	byIdentifier(iotc).each!(a => output.insert(internString(a)));
1168 }
1169 
1170 static istring convertChainToImportPath(const IdentifierChain ic)
1171 {
1172 	import std.path : dirSeparator;
1173 	import std.array : appender;
1174 	auto app = appender!(char[])();
1175 	foreach (i, ident; ic.identifiers)
1176 	{
1177 		app.put(ident.text);
1178 		if (i + 1 < ic.identifiers.length)
1179 			app.put(dirSeparator);
1180 	}
1181 	return internString(cast(string) app.data);
1182 }
1183 
1184 class InitializerVisitor : ASTVisitor
1185 {
1186 	this (TypeLookup* lookup, bool appendForeach = false)
1187 	{
1188 		this.lookup = lookup;
1189 		this.appendForeach = appendForeach;
1190 	}
1191 
1192 	alias visit = ASTVisitor.visit;
1193 
1194 	override void visit(const IdentifierOrTemplateInstance ioti)
1195 	{
1196 		if (on && ioti.identifier != tok!"")
1197 			lookup.breadcrumbs.insert(internString(ioti.identifier.text));
1198 		else if (on && ioti.templateInstance.identifier != tok!"")
1199 			lookup.breadcrumbs.insert(internString(ioti.templateInstance.identifier.text));
1200 		ioti.accept(this);
1201 	}
1202 
1203 	override void visit(const PrimaryExpression primary)
1204 	{
1205 		// Add identifiers without processing. Convert literals to strings with
1206 		// the prefix '*' so that that the second pass can tell the difference
1207 		// between "int.abc" and "10.abc".
1208 		if (on && primary.basicType != tok!"")
1209 			lookup.breadcrumbs.insert(internString(str(primary.basicType.type)));
1210 		if (on) switch (primary.primary.type)
1211 		{
1212 		case tok!"identifier":
1213 			lookup.breadcrumbs.insert(internString(primary.primary.text));
1214 			break;
1215 		case tok!"doubleLiteral":
1216 			lookup.breadcrumbs.insert(DOUBLE_LITERAL_SYMBOL_NAME);
1217 			break;
1218 		case tok!"floatLiteral":
1219 			lookup.breadcrumbs.insert(FLOAT_LITERAL_SYMBOL_NAME);
1220 			break;
1221 		case tok!"idoubleLiteral":
1222 			lookup.breadcrumbs.insert(IDOUBLE_LITERAL_SYMBOL_NAME);
1223 			break;
1224 		case tok!"ifloatLiteral":
1225 			lookup.breadcrumbs.insert(IFLOAT_LITERAL_SYMBOL_NAME);
1226 			break;
1227 		case tok!"intLiteral":
1228 			lookup.breadcrumbs.insert(INT_LITERAL_SYMBOL_NAME);
1229 			break;
1230 		case tok!"longLiteral":
1231 			lookup.breadcrumbs.insert(LONG_LITERAL_SYMBOL_NAME);
1232 			break;
1233 		case tok!"realLiteral":
1234 			lookup.breadcrumbs.insert(REAL_LITERAL_SYMBOL_NAME);
1235 			break;
1236 		case tok!"irealLiteral":
1237 			lookup.breadcrumbs.insert(IREAL_LITERAL_SYMBOL_NAME);
1238 			break;
1239 		case tok!"uintLiteral":
1240 			lookup.breadcrumbs.insert(UINT_LITERAL_SYMBOL_NAME);
1241 			break;
1242 		case tok!"ulongLiteral":
1243 			lookup.breadcrumbs.insert(ULONG_LITERAL_SYMBOL_NAME);
1244 			break;
1245 		case tok!"characterLiteral":
1246 			lookup.breadcrumbs.insert(CHAR_LITERAL_SYMBOL_NAME);
1247 			break;
1248 		case tok!"dstringLiteral":
1249 			lookup.breadcrumbs.insert(DSTRING_LITERAL_SYMBOL_NAME);
1250 			break;
1251 		case tok!"stringLiteral":
1252 			lookup.breadcrumbs.insert(STRING_LITERAL_SYMBOL_NAME);
1253 			break;
1254 		case tok!"wstringLiteral":
1255 			lookup.breadcrumbs.insert(WSTRING_LITERAL_SYMBOL_NAME);
1256 			break;
1257 		case tok!"false":
1258 		case tok!"true":
1259 			lookup.breadcrumbs.insert(BOOL_VALUE_SYMBOL_NAME);
1260 			break;
1261 		default:
1262 			break;
1263 		}
1264 		primary.accept(this);
1265 	}
1266 
1267 	override void visit(const IndexExpression index)
1268 	{
1269 		lookup.breadcrumbs.insert(ARRAY_SYMBOL_NAME);
1270 		index.accept(this);
1271 	}
1272 
1273 	override void visit(const Initializer initializer)
1274 	{
1275 		on = true;
1276 		initializer.accept(this);
1277 		on = false;
1278 	}
1279 
1280 	override void visit(const ArrayInitializer ai)
1281 	{
1282 		lookup.breadcrumbs.insert(ARRAY_SYMBOL_NAME);
1283 		ai.accept(this);
1284 	}
1285 
1286 	// Skip these
1287 	override void visit(const ArgumentList) {}
1288 	override void visit(const NewAnonClassExpression) {}
1289 
1290 	override void visit(const Expression expression)
1291 	{
1292 		on = true;
1293 		expression.accept(this);
1294 		if (appendForeach)
1295 			lookup.breadcrumbs.insert(internString("foreach"));
1296 		on = false;
1297 	}
1298 
1299 	override void visit(const ExpressionNode expression)
1300 	{
1301 		on = true;
1302 		expression.accept(this);
1303 		if (appendForeach)
1304 			lookup.breadcrumbs.insert(internString("foreach"));
1305 		on = false;
1306 	}
1307 
1308 	TypeLookup* lookup;
1309 	bool on = false;
1310 	const bool appendForeach;
1311 }