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.gc_allocator : GCAllocator;
38 import std.experimental.logger;
39 import std.typecons : Rebindable;
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 	alias SymbolAllocator = GCAllocator; // NOTE using First`Pass.symbolAllocator` instead fails when analyzing Phobos master
57 	alias ScopeAllocator = GCAllocator; // NOTE using `Mallocator` instead fails when analyzing Phobos master
58 
59 	/**
60 	 * Params:
61 	 *     mod = the module to visit
62 	 *     symbolFile = path to the file being converted
63 	 *     symbolAllocator = allocator used for the auto-complete symbols
64 	 *     semanticAllocator = allocator used for semantic symbols
65 	 *     includeParameterSymbols = include parameter symbols as children of
66 	 *         function decalarations and constructors
67 	 */
68 	this(const Module mod, istring symbolFile, IAllocator symbolAllocator,
69 		IAllocator semanticAllocator, bool includeParameterSymbols,
70 		ModuleCache* cache, CacheEntry* entry = null)
71 	in
72 	{
73 		assert(mod);
74 		assert(symbolAllocator);
75 		assert(semanticAllocator);
76 		assert(cache);
77 	}
78 	do
79 	{
80 		this.mod = mod;
81 		this.symbolFile = symbolFile;
82 		this.symbolAllocator = symbolAllocator;
83 		this.semanticAllocator = semanticAllocator;
84 		this.includeParameterSymbols = includeParameterSymbols;
85 		this.entry = entry;
86 		this.cache = cache;
87 	}
88 
89 	/**
90 	 * Runs the against the AST and produces symbols.
91 	 */
92 	void run()
93 	{
94 		visit(mod);
95 	}
96 
97 	override void visit(const Unittest u)
98 	{
99 		// Create a dummy symbol because we don't want unit test symbols leaking
100 		// into the symbol they're declared in.
101 		pushSymbol(UNITTEST_SYMBOL_NAME,
102 			CompletionKind.dummy, istring(null));
103 		scope(exit) popSymbol();
104 		u.accept(this);
105 	}
106 
107 	override void visit(const Constructor con)
108 	{
109 		visitConstructor(con.location, con.parameters, con.templateParameters, con.functionBody, con.comment);
110 	}
111 
112 	override void visit(const SharedStaticConstructor con)
113 	{
114 		visitConstructor(con.location, null, null, con.functionBody, con.comment);
115 	}
116 
117 	override void visit(const StaticConstructor con)
118 	{
119 		visitConstructor(con.location, null, null, con.functionBody, con.comment);
120 	}
121 
122 	override void visit(const Destructor des)
123 	{
124 		visitDestructor(des.index, des.functionBody, des.comment);
125 	}
126 
127 	override void visit(const SharedStaticDestructor des)
128 	{
129 		visitDestructor(des.location, des.functionBody, des.comment);
130 	}
131 
132 	override void visit(const StaticDestructor des)
133 	{
134 		visitDestructor(des.location, des.functionBody, des.comment);
135 	}
136 
137 	override void visit(const FunctionDeclaration dec)
138 	{
139 		assert(dec);
140 		pushSymbol(dec.name.text, CompletionKind.functionName, symbolFile,
141 				dec.name.index, dec.returnType);
142 		scope (exit) popSymbol();
143 		currentSymbol.acSymbol.protection = protection.current;
144 		currentSymbol.acSymbol.doc = makeDocumentation(dec.comment);
145 
146 		istring lastComment = this.lastComment;
147 		this.lastComment = istring.init;
148 		scope(exit) this.lastComment = lastComment;
149 
150 		if (dec.functionBody !is null)
151 		{
152 			pushFunctionScope(dec.functionBody, semanticAllocator,
153 					dec.name.index + dec.name.text.length);
154 			scope (exit) popScope();
155 			processParameters(currentSymbol, dec.returnType,
156 					currentSymbol.acSymbol.name, dec.parameters, dec.templateParameters);
157 			dec.functionBody.accept(this);
158 		}
159 		else
160 		{
161 			immutable ips = includeParameterSymbols;
162 			includeParameterSymbols = false;
163 			processParameters(currentSymbol, dec.returnType,
164 					currentSymbol.acSymbol.name, dec.parameters, dec.templateParameters);
165 			includeParameterSymbols = ips;
166 		}
167 	}
168 
169 	override void visit(const FunctionLiteralExpression exp)
170 	{
171 		assert(exp);
172 
173 		auto fbody = exp.specifiedFunctionBody;
174 		if (fbody is null)
175 			return;
176 		auto block = fbody.blockStatement;
177 		if (block is null)
178 			return;
179 
180 		pushSymbol(FUNCTION_LITERAL_SYMBOL_NAME, CompletionKind.dummy, symbolFile,
181 			block.startLocation, null);
182 		scope(exit) popSymbol();
183 
184 		pushScope(block.startLocation, block.endLocation);
185 		scope (exit) popScope();
186 		processParameters(currentSymbol, exp.returnType,
187 				FUNCTION_LITERAL_SYMBOL_NAME, exp.parameters, null);
188 		block.accept(this);
189 	}
190 
191 	override void visit(const ClassDeclaration dec)
192 	{
193 		visitAggregateDeclaration(dec, CompletionKind.className);
194 	}
195 
196 	override void visit(const TemplateDeclaration dec)
197 	{
198 		visitAggregateDeclaration(dec, CompletionKind.templateName);
199 	}
200 
201 	override void visit(const InterfaceDeclaration dec)
202 	{
203 		visitAggregateDeclaration(dec, CompletionKind.interfaceName);
204 	}
205 
206 	override void visit(const UnionDeclaration dec)
207 	{
208 		visitAggregateDeclaration(dec, CompletionKind.unionName);
209 	}
210 
211 	override void visit(const StructDeclaration dec)
212 	{
213 		visitAggregateDeclaration(dec, CompletionKind.structName);
214 	}
215 
216 	override void visit(const NewAnonClassExpression nace)
217 	{
218 		// its base classes would be added as "inherit" breadcrumbs in the current symbol
219 		skipBaseClassesOfNewAnon = true;
220 		nace.accept(this);
221 		skipBaseClassesOfNewAnon = false;
222 	}
223 
224 	override void visit(const BaseClass bc)
225 	{
226 		if (skipBaseClassesOfNewAnon)
227 			return;
228 		if (bc.type2.typeIdentifierPart is null ||
229 			bc.type2.typeIdentifierPart.identifierOrTemplateInstance is null)
230 			return;
231 		auto lookup = TypeLookupsAllocator.instance.make!TypeLookup(TypeLookupKind.inherit);
232 		writeIotcTo(bc.type2.typeIdentifierPart, lookup.breadcrumbs);
233 		currentSymbol.typeLookups.insert(lookup);
234 
235 		// create an alias to the BaseClass to allow completions
236 		// of the form : `instance.BaseClass.`, which is
237 		// mostly used to bypass the most derived overrides.
238 		const idt = lookup.breadcrumbs.back;
239 		if (!idt.length)
240 			return;
241 		SemanticSymbol* symbol = allocateSemanticSymbol(idt,
242 			CompletionKind.aliasName, symbolFile, currentScope.endLocation);
243 		Type t = TypeLookupsAllocator.instance.make!Type;
244 		t.type2 = cast() bc.type2;
245 		addTypeToLookups(symbol.typeLookups, t);
246 		symbol.parent = currentSymbol;
247 		currentSymbol.addChild(symbol, true);
248 		symbol.acSymbol.protection = protection.current;
249 	}
250 
251 	override void visit(const VariableDeclaration dec)
252 	{
253 		assert (currentSymbol);
254 		foreach (declarator; dec.declarators)
255 		{
256 			SemanticSymbol* symbol = allocateSemanticSymbol(
257 				declarator.name.text, CompletionKind.variableName,
258 				symbolFile, declarator.name.index);
259 			if (dec.type !is null)
260 				addTypeToLookups(symbol.typeLookups, dec.type);
261 			symbol.parent = currentSymbol;
262 			symbol.acSymbol.protection = protection.current;
263 			symbol.acSymbol.doc = makeDocumentation(declarator.comment);
264 			currentSymbol.addChild(symbol, true);
265 			currentScope.addSymbol(symbol.acSymbol, false);
266 
267 			if (currentSymbol.acSymbol.kind == CompletionKind.structName
268 				|| currentSymbol.acSymbol.kind == CompletionKind.unionName)
269 			{
270 				structFieldNames.insert(symbol.acSymbol.name);
271 				// TODO: remove this cast. See the note on structFieldTypes
272 				structFieldTypes.insert(cast() dec.type);
273 			}
274 		}
275 		if (dec.autoDeclaration !is null)
276 		{
277 			foreach (part; dec.autoDeclaration.parts)
278 			{
279 				SemanticSymbol* symbol = allocateSemanticSymbol(
280 					part.identifier.text, CompletionKind.variableName,
281 					symbolFile, part.identifier.index);
282 				symbol.parent = currentSymbol;
283 				populateInitializer(symbol, part.initializer);
284 				symbol.acSymbol.protection = protection.current;
285 				symbol.acSymbol.doc = makeDocumentation(dec.comment);
286 				currentSymbol.addChild(symbol, true);
287 				currentScope.addSymbol(symbol.acSymbol, false);
288 
289 				if (currentSymbol.acSymbol.kind == CompletionKind.structName
290 					|| currentSymbol.acSymbol.kind == CompletionKind.unionName)
291 				{
292 					structFieldNames.insert(symbol.acSymbol.name);
293 					// TODO: remove this cast. See the note on structFieldTypes
294 					structFieldTypes.insert(null);
295 				}
296 			}
297 		}
298 	}
299 
300 	override void visit(const AliasDeclaration aliasDeclaration)
301 	{
302 		if (aliasDeclaration.initializers.length == 0)
303 		{
304 			foreach (name; aliasDeclaration.declaratorIdentifierList.identifiers)
305 			{
306 				SemanticSymbol* symbol = allocateSemanticSymbol(
307 					name.text, CompletionKind.aliasName, symbolFile, name.index);
308 				if (aliasDeclaration.type !is null)
309 					addTypeToLookups(symbol.typeLookups, aliasDeclaration.type);
310 				symbol.parent = currentSymbol;
311 				currentSymbol.addChild(symbol, true);
312 				currentScope.addSymbol(symbol.acSymbol, false);
313 				symbol.acSymbol.protection = protection.current;
314 				symbol.acSymbol.doc = makeDocumentation(aliasDeclaration.comment);
315 			}
316 		}
317 		else
318 		{
319 			foreach (initializer; aliasDeclaration.initializers)
320 			{
321 				SemanticSymbol* symbol = allocateSemanticSymbol(
322 					initializer.name.text, CompletionKind.aliasName,
323 					symbolFile, initializer.name.index);
324 				if (initializer.type !is null)
325 					addTypeToLookups(symbol.typeLookups, initializer.type);
326 				symbol.parent = currentSymbol;
327 				currentSymbol.addChild(symbol, true);
328 				currentScope.addSymbol(symbol.acSymbol, false);
329 				symbol.acSymbol.protection = protection.current;
330 				symbol.acSymbol.doc = makeDocumentation(aliasDeclaration.comment);
331 			}
332 		}
333 	}
334 
335 	override void visit(const AliasThisDeclaration dec)
336 	{
337 		const k = currentSymbol.acSymbol.kind;
338 		if (k != CompletionKind.structName && k != CompletionKind.className &&
339 			k != CompletionKind.unionName && k != CompletionKind.mixinTemplateName)
340 		{
341 			return;
342 		}
343 		currentSymbol.typeLookups.insert(TypeLookupsAllocator.instance.make!TypeLookup(
344 			internString(dec.identifier.text), TypeLookupKind.aliasThis));
345 	}
346 
347 	override void visit(const Declaration dec)
348 	{
349 		if (dec.attributeDeclaration !is null
350 			&& isProtection(dec.attributeDeclaration.attribute.attribute.type))
351 		{
352 			protection.addScope(dec.attributeDeclaration.attribute.attribute.type);
353 			return;
354 		}
355 		IdType p;
356 		foreach (const Attribute attr; dec.attributes)
357 		{
358 			if (isProtection(attr.attribute.type))
359 				p = attr.attribute.type;
360 		}
361 		if (p != tok!"")
362 		{
363 			protection.beginLocal(p);
364 			if (dec.declarations.length > 0)
365 			{
366 				protection.beginScope();
367 				dec.accept(this);
368 				protection.endScope();
369 			}
370 			else
371 				dec.accept(this);
372 			protection.endLocal();
373 		}
374 		else
375 			dec.accept(this);
376 	}
377 
378 	override void visit(const Module mod)
379 	{
380 		rootSymbol = allocateSemanticSymbol(null, CompletionKind.moduleName,
381 			symbolFile);
382 		currentSymbol = rootSymbol;
383 		moduleScope = GCAllocator.instance.make!Scope(0, uint.max); // NOTE using `semanticAllocator` here fails as `Segmentation fault (core dumped)`
384 		currentScope = moduleScope;
385 		auto objectLocation = cache.resolveImportLocation("object");
386 		if (objectLocation is null)
387 			warning("Could not locate object.d or object.di");
388 		else
389 		{
390 			auto objectImport = allocateSemanticSymbol(IMPORT_SYMBOL_NAME,
391 				CompletionKind.importSymbol, objectLocation);
392 			objectImport.acSymbol.skipOver = true;
393 			currentSymbol.addChild(objectImport, true);
394 			currentScope.addSymbol(objectImport.acSymbol, false);
395 		}
396 		foreach (s; builtinSymbols[])
397 			currentScope.addSymbol(s, false);
398 		mod.accept(this);
399 	}
400 
401 	override void visit(const EnumDeclaration dec)
402 	{
403 		assert (currentSymbol);
404 		SemanticSymbol* symbol = allocateSemanticSymbol(dec.name.text,
405 			CompletionKind.enumName, symbolFile, dec.name.index);
406 		if (dec.type !is null)
407 			addTypeToLookups(symbol.typeLookups, dec.type);
408 		symbol.acSymbol.addChildren(enumSymbols[], false);
409 		symbol.parent = currentSymbol;
410 		currentSymbol.addChild(symbol, true);
411 		currentScope.addSymbol(symbol.acSymbol, false);
412 		symbol.acSymbol.doc = makeDocumentation(dec.comment);
413 
414 		istring lastComment = this.lastComment;
415 		this.lastComment = istring.init;
416 		scope(exit) this.lastComment = lastComment;
417 
418 		currentSymbol = symbol;
419 
420 		if (dec.enumBody !is null)
421 		{
422 			pushScope(dec.enumBody.startLocation, dec.enumBody.endLocation);
423 			dec.enumBody.accept(this);
424 			popScope();
425 		}
426 
427 		currentSymbol = currentSymbol.parent;
428 	}
429 
430 	mixin visitEnumMember!EnumMember;
431 	mixin visitEnumMember!AnonymousEnumMember;
432 
433 	override void visit(const ModuleDeclaration moduleDeclaration)
434 	{
435 		const parts = moduleDeclaration.moduleName.identifiers;
436 		rootSymbol.acSymbol.name = internString(parts.length ? parts[$ - 1].text : null);
437 	}
438 
439 	override void visit(const StructBody structBody)
440 	{
441 		import std.algorithm : move;
442 
443 		pushScope(structBody.startLocation, structBody.endLocation);
444 		scope (exit) popScope();
445 		protection.beginScope();
446 		scope (exit) protection.endScope();
447 
448 		auto savedStructFieldNames = move(structFieldNames);
449 		auto savedStructFieldTypes = move(structFieldTypes);
450 		scope(exit) structFieldNames = move(savedStructFieldNames);
451 		scope(exit) structFieldTypes = move(savedStructFieldTypes);
452 
453 		DSymbol* thisSymbol = SymbolAllocator.instance.make!DSymbol(THIS_SYMBOL_NAME,
454 			CompletionKind.variableName, currentSymbol.acSymbol);
455 		thisSymbol.location = currentScope.startLocation;
456 		thisSymbol.symbolFile = symbolFile;
457 		thisSymbol.type = currentSymbol.acSymbol;
458 		thisSymbol.ownType = false;
459 		currentScope.addSymbol(thisSymbol, false);
460 
461 		foreach (dec; structBody.declarations)
462 			visit(dec);
463 
464 		// If no constructor is found, generate one
465 		if ((currentSymbol.acSymbol.kind == CompletionKind.structName
466 				|| currentSymbol.acSymbol.kind == CompletionKind.unionName)
467 				&& currentSymbol.acSymbol.getFirstPartNamed(CONSTRUCTOR_SYMBOL_NAME) is null)
468 			createConstructor();
469 	}
470 
471 	override void visit(const ImportDeclaration importDeclaration)
472 	{
473 		import std.algorithm : filter, map;
474 		import std.path : buildPath;
475 		import std.typecons : Tuple;
476 
477 		foreach (single; importDeclaration.singleImports.filter!(
478 			a => a !is null && a.identifierChain !is null))
479 		{
480 			immutable importPath = convertChainToImportPath(single.identifierChain);
481 			istring modulePath = cache.resolveImportLocation(importPath);
482 			if (modulePath is null)
483 			{
484 				warning("Could not resolve location of module '", importPath.data, "'");
485 				continue;
486 			}
487 			SemanticSymbol* importSymbol = allocateSemanticSymbol(IMPORT_SYMBOL_NAME,
488 				CompletionKind.importSymbol, modulePath);
489 			importSymbol.acSymbol.skipOver = protection.currentForImport != tok!"public";
490 			if (single.rename == tok!"")
491 			{
492 				size_t i = 0;
493 				DSymbol* currentImportSymbol;
494 				foreach (p; single.identifierChain.identifiers.map!(a => a.text))
495 				{
496 					immutable bool first = i == 0;
497 					immutable bool last = i + 1 >= single.identifierChain.identifiers.length;
498 					immutable CompletionKind kind = last ? CompletionKind.moduleName
499 						: CompletionKind.packageName;
500 					istring ip = internString(p);
501 					if (first)
502 					{
503 						auto s = currentScope.getSymbolsByName(ip);
504 						if (s.length == 0)
505 						{
506 							currentImportSymbol = SymbolAllocator.instance.make!DSymbol(ip, kind);
507 							currentScope.addSymbol(currentImportSymbol, true);
508 							if (last)
509 							{
510 								currentImportSymbol.symbolFile = modulePath;
511 								currentImportSymbol.type = importSymbol.acSymbol;
512 								currentImportSymbol.ownType = false;
513 							}
514 						}
515 						else
516 							currentImportSymbol = s[0];
517 					}
518 					else
519 					{
520 						auto s = currentImportSymbol.getPartsByName(ip);
521 						if (s.length == 0)
522 						{
523 							auto sym = SymbolAllocator.instance.make!DSymbol(ip, kind);
524 							currentImportSymbol.addChild(sym, true);
525 							currentImportSymbol = sym;
526 							if (last)
527 							{
528 								currentImportSymbol.symbolFile = modulePath;
529 								currentImportSymbol.type = importSymbol.acSymbol;
530 								currentImportSymbol.ownType = false;
531 							}
532 						}
533 						else
534 							currentImportSymbol = s[0];
535 					}
536 					i++;
537 				}
538 				currentSymbol.addChild(importSymbol, true);
539 				currentScope.addSymbol(importSymbol.acSymbol, false);
540 			}
541 			else
542 			{
543 				SemanticSymbol* renameSymbol = allocateSemanticSymbol(
544 					internString(single.rename.text), CompletionKind.aliasName,
545 					modulePath);
546 				renameSymbol.acSymbol.skipOver = protection.currentForImport != tok!"public";
547 				renameSymbol.acSymbol.type = importSymbol.acSymbol;
548 				renameSymbol.acSymbol.ownType = true;
549 				renameSymbol.addChild(importSymbol, true);
550 				currentSymbol.addChild(renameSymbol, true);
551 				currentScope.addSymbol(renameSymbol.acSymbol, false);
552 			}
553 			if (entry !is null)
554 				entry.dependencies.insert(modulePath);
555 		}
556 		if (importDeclaration.importBindings is null) return;
557 		if (importDeclaration.importBindings.singleImport.identifierChain is null) return;
558 
559 		immutable chain = convertChainToImportPath(importDeclaration.importBindings.singleImport.identifierChain);
560 		istring modulePath = cache.resolveImportLocation(chain);
561 		if (modulePath is null)
562 		{
563 			warning("Could not resolve location of module '", chain, "'");
564 			return;
565 		}
566 
567 		foreach (bind; importDeclaration.importBindings.importBinds)
568 		{
569 			TypeLookup* lookup = TypeLookupsAllocator.instance.make!TypeLookup(
570 				TypeLookupKind.selectiveImport);
571 
572 			immutable bool isRenamed = bind.right != tok!"";
573 
574 			// The second phase must change this `importSymbol` kind to
575 			// `aliasName` for symbol lookup to work.
576 			SemanticSymbol* importSymbol = allocateSemanticSymbol(
577 				isRenamed ? bind.left.text : IMPORT_SYMBOL_NAME,
578 				CompletionKind.importSymbol, modulePath);
579 
580 			if (isRenamed)
581 			{
582 				lookup.breadcrumbs.insert(internString(bind.right.text));
583 				importSymbol.acSymbol.location = bind.left.index;
584 				importSymbol.acSymbol.altFile = symbolFile;
585 			}
586 			lookup.breadcrumbs.insert(internString(bind.left.text));
587 
588 			importSymbol.acSymbol.qualifier = SymbolQualifier.selectiveImport;
589 			importSymbol.typeLookups.insert(lookup);
590 			importSymbol.acSymbol.skipOver = protection.currentForImport != tok!"public";
591 			currentSymbol.addChild(importSymbol, true);
592 			currentScope.addSymbol(importSymbol.acSymbol, false);
593 		}
594 
595 		if (entry !is null)
596 			entry.dependencies.insert(modulePath);
597 	}
598 
599 	// Create scope for block statements
600 	override void visit(const BlockStatement blockStatement)
601 	{
602 		if (blockStatement.declarationsAndStatements !is null)
603 		{
604 			pushScope(blockStatement.startLocation, blockStatement.endLocation);
605 			scope(exit) popScope();
606 			visit (blockStatement.declarationsAndStatements);
607 		}
608 	}
609 
610 	// Create attribute/protection scope for conditional compilation declaration
611 	// blocks.
612 	override void visit(const ConditionalDeclaration conditionalDecl)
613 	{
614 		if (conditionalDecl.compileCondition !is null)
615 			visit(conditionalDecl.compileCondition);
616 
617 		if (conditionalDecl.trueDeclarations.length)
618 		{
619 			protection.beginScope();
620 			scope (exit) protection.endScope();
621 
622 			foreach (decl; conditionalDecl.trueDeclarations)
623 				if (decl !is null)
624 					visit (decl);
625 		}
626 
627 		if (conditionalDecl.falseDeclarations.length)
628 		{
629 			protection.beginScope();
630 			scope (exit) protection.endScope();
631 
632 			foreach (decl; conditionalDecl.falseDeclarations)
633 				if (decl !is null)
634 					visit (decl);
635 		}
636 	}
637 
638 	override void visit(const TemplateMixinExpression tme)
639 	{
640 		// TODO: support typeof here
641 		if (tme.mixinTemplateName.symbol is null)
642 			return;
643 		const Symbol sym = tme.mixinTemplateName.symbol;
644 		auto lookup = TypeLookupsAllocator.instance.make!TypeLookup(TypeLookupKind.mixinTemplate);
645 
646 		writeIotcTo(tme.mixinTemplateName.symbol.identifierOrTemplateChain,
647 			lookup.breadcrumbs);
648 
649 		if (currentSymbol.acSymbol.kind != CompletionKind.functionName)
650 			currentSymbol.typeLookups.insert(lookup);
651 
652 		/* If the mixin is named then do like if `mixin F f;` would be `mixin F; alias f = F;`
653 		which's been empirically verified to produce the right completions for `f.`,
654 		*/
655 		if (tme.identifier != tok!"" && sym.identifierOrTemplateChain &&
656 			sym.identifierOrTemplateChain.identifiersOrTemplateInstances.length)
657 		{
658 			SemanticSymbol* symbol = allocateSemanticSymbol(tme.identifier.text,
659 				CompletionKind.aliasName, symbolFile, tme.identifier.index);
660 			Type tp = TypeLookupsAllocator.instance.make!Type;
661 			tp.type2 = TypeLookupsAllocator.instance.make!Type2;
662 			TypeIdentifierPart root;
663 			TypeIdentifierPart current;
664 			foreach(ioti; sym.identifierOrTemplateChain.identifiersOrTemplateInstances)
665 			{
666 				TypeIdentifierPart old = current;
667 				current = TypeLookupsAllocator.instance.make!TypeIdentifierPart;
668 				if (old)
669 				{
670 					old.typeIdentifierPart = current;
671 				}
672 				else
673 				{
674 					root = current;
675 				}
676 				current.identifierOrTemplateInstance = cast() ioti;
677 			}
678 			tp.type2.typeIdentifierPart = root;
679 			addTypeToLookups(symbol.typeLookups, tp);
680 			symbol.parent = currentSymbol;
681 			currentSymbol.addChild(symbol, true);
682 			currentScope.addSymbol(symbol.acSymbol, false);
683 			symbol.acSymbol.protection = protection.current;
684 		}
685 	}
686 
687 	override void visit(const ForeachStatement feStatement)
688 	{
689 		if (feStatement.declarationOrStatement !is null
690 			&& feStatement.declarationOrStatement.statement !is null
691 			&& feStatement.declarationOrStatement.statement.statementNoCaseNoDefault !is null
692 			&& feStatement.declarationOrStatement.statement.statementNoCaseNoDefault.blockStatement !is null)
693 		{
694 			const BlockStatement bs =
695 				feStatement.declarationOrStatement.statement.statementNoCaseNoDefault.blockStatement;
696 			pushScope(feStatement.startIndex, bs.endLocation);
697 			scope(exit) popScope();
698 			feExpression = feStatement.low.items[$ - 1];
699 			feStatement.accept(this);
700 			feExpression = null;
701 		}
702 		else
703 		{
704 			const ubyte o1 = foreachTypeIndexOfInterest;
705 			const ubyte o2 = foreachTypeIndex;
706 			feStatement.accept(this);
707 			foreachTypeIndexOfInterest = o1;
708 			foreachTypeIndex = o2;
709 		}
710 	}
711 
712 	override void visit(const ForeachTypeList feTypeList)
713 	{
714 		foreachTypeIndex = 0;
715 		foreachTypeIndexOfInterest = cast(ubyte)(feTypeList.items.length - 1);
716 		feTypeList.accept(this);
717 	}
718 
719 	override void visit(const ForeachType feType)
720 	{
721 		if (foreachTypeIndex++ == foreachTypeIndexOfInterest)
722 		{
723 			SemanticSymbol* symbol = allocateSemanticSymbol(feType.identifier.text,
724 				CompletionKind.variableName, symbolFile, feType.identifier.index);
725 			if (feType.type !is null)
726 				addTypeToLookups(symbol.typeLookups, feType.type);
727 			symbol.parent = currentSymbol;
728 			currentSymbol.addChild(symbol, true);
729 			currentScope.addSymbol(symbol.acSymbol, true);
730 			if (symbol.typeLookups.empty && feExpression !is null)
731 				populateInitializer(symbol, feExpression, true);
732 		}
733 	}
734 
735 	override void visit(const IfStatement ifs)
736 	{
737 		if (ifs.identifier != tok!"" && ifs.thenStatement)
738 		{
739 			pushScope(ifs.thenStatement.startLocation, ifs.thenStatement.endLocation);
740 			scope(exit) popScope();
741 
742 			SemanticSymbol* symbol = allocateSemanticSymbol(ifs.identifier.text,
743 				CompletionKind.variableName, symbolFile, ifs.identifier.index);
744 			if (ifs.type !is null)
745 				addTypeToLookups(symbol.typeLookups, ifs.type);
746 			symbol.parent = currentSymbol;
747 			currentSymbol.addChild(symbol, true);
748 			currentScope.addSymbol(symbol.acSymbol, true);
749 			if (symbol.typeLookups.empty && ifs.expression !is null)
750 				populateInitializer(symbol, ifs.expression, false);
751 		}
752 		ifs.accept(this);
753 	}
754 
755 	override void visit(const WithStatement withStatement)
756 	{
757 		if (withStatement.expression !is null
758 			&& withStatement.declarationOrStatement !is null)
759 		{
760 			pushScope(withStatement.declarationOrStatement.startLocation,
761 				withStatement.declarationOrStatement.endLocation);
762 			scope(exit) popScope();
763 
764 			pushSymbol(WITH_SYMBOL_NAME, CompletionKind.withSymbol, symbolFile,
765 				currentScope.startLocation, null);
766 			scope(exit) popSymbol();
767 
768 			populateInitializer(currentSymbol, withStatement.expression, false);
769 			withStatement.accept(this);
770 
771 		}
772 		else
773 			withStatement.accept(this);
774 	}
775 
776 	override void visit(const ArgumentList list)
777 	{
778 		scope visitor = new ArgumentListVisitor(this);
779 		visitor.visit(list);
780 	}
781 
782 	alias visit = ASTVisitor.visit;
783 
784 	/// Module scope
785 	Scope* moduleScope;
786 
787 	/// The module
788 	SemanticSymbol* rootSymbol;
789 
790 	/// Allocator used for symbol allocation
791 	IAllocator symbolAllocator;
792 
793 	/// Number of symbols allocated
794 	uint symbolsAllocated;
795 
796 private:
797 
798 	void createConstructor()
799 	{
800 		import std.array : appender;
801 		import std.range : zip;
802 
803 		auto app = appender!string();
804 		app.put("this(");
805 		bool first = true;
806 		foreach (field; zip(structFieldTypes[], structFieldNames[]))
807 		{
808 			if (first)
809 				first = false;
810 			else
811 				app.put(", ");
812 			if (field[0] is null)
813 				app.put("auto ");
814 			else
815 			{
816 				app.formatNode(field[0]);
817 				app.put(" ");
818 			}
819 			app.put(field[1].data);
820 		}
821 		app.put(")");
822 		SemanticSymbol* symbol = allocateSemanticSymbol(CONSTRUCTOR_SYMBOL_NAME,
823 			CompletionKind.functionName, symbolFile, currentSymbol.acSymbol.location);
824 		symbol.acSymbol.callTip = istring(app.data);
825 		currentSymbol.addChild(symbol, true);
826 	}
827 
828 	void pushScope(size_t startLocation, size_t endLocation)
829 	{
830 		assert (startLocation < uint.max);
831 		assert (endLocation < uint.max || endLocation == size_t.max);
832 		Scope* s = ScopeAllocator.instance.make!Scope(cast(uint) startLocation, cast(uint) endLocation);
833 		s.parent = currentScope;
834 		currentScope.children.insert(s);
835 		currentScope = s;
836 	}
837 
838 	void popScope()
839 	{
840 		currentScope = currentScope.parent;
841 	}
842 
843 	void pushFunctionScope(const FunctionBody functionBody,
844 		IAllocator semanticAllocator, size_t scopeBegin)
845 	{
846 		Scope* s = ScopeAllocator.instance.make!Scope(cast(uint) scopeBegin,
847 			cast(uint) functionBody.endLocation);
848 		s.parent = currentScope;
849 		currentScope.children.insert(s);
850 		currentScope = s;
851 	}
852 
853 	void pushSymbol(string name, CompletionKind kind, istring symbolFile,
854 		size_t location = 0, const Type type = null)
855 	{
856 		SemanticSymbol* symbol = allocateSemanticSymbol(name, kind, symbolFile,
857 			location);
858 		if (type !is null)
859 			addTypeToLookups(symbol.typeLookups, type);
860 		symbol.parent = currentSymbol;
861 		currentSymbol.addChild(symbol, true);
862 		currentScope.addSymbol(symbol.acSymbol, false);
863 		currentSymbol = symbol;
864 	}
865 
866 	void popSymbol()
867 	{
868 		currentSymbol = currentSymbol.parent;
869 	}
870 
871 	template visitEnumMember(T)
872 	{
873 		override void visit(const T member)
874 		{
875 			pushSymbol(member.name.text, CompletionKind.enumMember, symbolFile,
876 				member.name.index, member.type);
877 			scope(exit) popSymbol();
878 			currentSymbol.acSymbol.doc = makeDocumentation(member.comment);
879 		}
880 	}
881 
882 	void visitAggregateDeclaration(AggType)(AggType dec, CompletionKind kind)
883 	{
884 		if ((kind == CompletionKind.unionName || kind == CompletionKind.structName) &&
885 			dec.name == tok!"")
886 		{
887 			dec.accept(this);
888 			return;
889 		}
890 		pushSymbol(dec.name.text, kind, symbolFile, dec.name.index);
891 		scope(exit) popSymbol();
892 
893 		if (kind == CompletionKind.className)
894 			currentSymbol.acSymbol.addChildren(classSymbols[], false);
895 		else
896 			currentSymbol.acSymbol.addChildren(aggregateSymbols[], false);
897 		currentSymbol.acSymbol.protection = protection.current;
898 		currentSymbol.acSymbol.doc = makeDocumentation(dec.comment);
899 
900 		istring lastComment = this.lastComment;
901 		this.lastComment = istring.init;
902 		scope(exit) this.lastComment = lastComment;
903 
904 		immutable size_t scopeBegin = dec.name.index + dec.name.text.length;
905 		static if (is (AggType == const(TemplateDeclaration)))
906 			immutable size_t scopeEnd = dec.endLocation;
907 		else
908 			immutable size_t scopeEnd = dec.structBody is null ? scopeBegin : dec.structBody.endLocation;
909 		pushScope(scopeBegin, scopeEnd);
910 		scope(exit) popScope();
911 		protection.beginScope();
912 		scope (exit) protection.endScope();
913 		processTemplateParameters(currentSymbol, dec.templateParameters);
914 		dec.accept(this);
915 	}
916 
917 	void visitConstructor(size_t location, const Parameters parameters,
918 		const TemplateParameters templateParameters,
919 		const FunctionBody functionBody, string doc)
920 	{
921 		SemanticSymbol* symbol = allocateSemanticSymbol(CONSTRUCTOR_SYMBOL_NAME,
922 			CompletionKind.functionName, symbolFile, location);
923 		symbol.parent = currentSymbol;
924 		currentSymbol.addChild(symbol, true);
925 		processParameters(symbol, null, THIS_SYMBOL_NAME, parameters, templateParameters);
926 		symbol.acSymbol.protection = protection.current;
927 		symbol.acSymbol.doc = makeDocumentation(doc);
928 
929 		istring lastComment = this.lastComment;
930 		this.lastComment = istring.init;
931 		scope(exit) this.lastComment = lastComment;
932 
933 		if (functionBody !is null)
934 		{
935 			pushFunctionScope(functionBody, semanticAllocator,
936 				location + 4); // 4 == "this".length
937 			scope(exit) popScope();
938 			currentSymbol = symbol;
939 			functionBody.accept(this);
940 			currentSymbol = currentSymbol.parent;
941 		}
942 	}
943 
944 	void visitDestructor(size_t location, const FunctionBody functionBody, string doc)
945 	{
946 		SemanticSymbol* symbol = allocateSemanticSymbol(DESTRUCTOR_SYMBOL_NAME,
947 			CompletionKind.functionName, symbolFile, location);
948 		symbol.parent = currentSymbol;
949 		currentSymbol.addChild(symbol, true);
950 		symbol.acSymbol.callTip = internString("~this()");
951 		symbol.acSymbol.protection = protection.current;
952 		symbol.acSymbol.doc = makeDocumentation(doc);
953 
954 		istring lastComment = this.lastComment;
955 		this.lastComment = istring.init;
956 		scope(exit) this.lastComment = lastComment;
957 
958 		if (functionBody !is null)
959 		{
960 			pushFunctionScope(functionBody, semanticAllocator, location + 4); // 4 == "this".length
961 			scope(exit) popScope();
962 			currentSymbol = symbol;
963 			functionBody.accept(this);
964 			currentSymbol = currentSymbol.parent;
965 		}
966 	}
967 
968 	void processParameters(SemanticSymbol* symbol, const Type returnType,
969 		string functionName, const Parameters parameters,
970 		const TemplateParameters templateParameters)
971 	{
972 		processTemplateParameters(symbol, templateParameters);
973 		if (includeParameterSymbols && parameters !is null)
974 		{
975 			foreach (const Parameter p; parameters.parameters)
976 			{
977 				SemanticSymbol* parameter = allocateSemanticSymbol(
978 					p.name.text, CompletionKind.variableName, symbolFile,
979 					p.name.index);
980 				if (p.type !is null)
981 					addTypeToLookups(parameter.typeLookups, p.type);
982 				parameter.parent = currentSymbol;
983 				currentSymbol.acSymbol.argNames.insert(parameter.acSymbol.name);
984 				currentSymbol.addChild(parameter, true);
985 				currentScope.addSymbol(parameter.acSymbol, false);
986 			}
987 			if (parameters.hasVarargs)
988 			{
989 				SemanticSymbol* argptr = allocateSemanticSymbol(ARGPTR_SYMBOL_NAME,
990 					CompletionKind.variableName, istring(null), size_t.max);
991 				addTypeToLookups(argptr.typeLookups, argptrType);
992 				argptr.parent = currentSymbol;
993 				currentSymbol.addChild(argptr, true);
994 				currentScope.addSymbol(argptr.acSymbol, false);
995 
996 				SemanticSymbol* arguments = allocateSemanticSymbol(
997 					ARGUMENTS_SYMBOL_NAME, CompletionKind.variableName,
998 					istring(null), size_t.max);
999 				addTypeToLookups(arguments.typeLookups, argumentsType);
1000 				arguments.parent = currentSymbol;
1001 				currentSymbol.addChild(arguments, true);
1002 				currentScope.addSymbol(arguments.acSymbol, false);
1003 			}
1004 		}
1005 		symbol.acSymbol.callTip = formatCallTip(returnType, functionName,
1006 			parameters, templateParameters);
1007 	}
1008 
1009 	void processTemplateParameters(SemanticSymbol* symbol, const TemplateParameters templateParameters)
1010 	{
1011 		if (includeParameterSymbols && templateParameters !is null
1012 				&& templateParameters.templateParameterList !is null)
1013 		{
1014 			foreach (const TemplateParameter p; templateParameters.templateParameterList.items)
1015 			{
1016 				string name;
1017 				CompletionKind kind;
1018 				size_t index;
1019 				Rebindable!(const(Type)) type;
1020 				if (p.templateAliasParameter !is null)
1021 				{
1022 					name = p.templateAliasParameter.identifier.text;
1023 					kind = CompletionKind.aliasName;
1024 					index = p.templateAliasParameter.identifier.index;
1025 				}
1026 				else if (p.templateTypeParameter !is null)
1027 				{
1028 					name = p.templateTypeParameter.identifier.text;
1029 					kind = CompletionKind.aliasName;
1030 					index = p.templateTypeParameter.identifier.index;
1031 					// even if templates are not solved we can get the completions
1032 					// for the type the template parameter implicitly converts to,
1033 					// which is often useful for aggregate types.
1034 					if (p.templateTypeParameter.colonType)
1035 						type = p.templateTypeParameter.colonType;
1036 					// otherwise just provide standard type properties
1037 					else
1038 						kind = CompletionKind.typeTmpParam;
1039 				}
1040 				else if (p.templateValueParameter !is null)
1041 				{
1042 					name = p.templateValueParameter.identifier.text;
1043 					kind = CompletionKind.variableName;
1044 					index = p.templateValueParameter.identifier.index;
1045 					type = p.templateValueParameter.type;
1046 				}
1047 				else if (p.templateTupleParameter !is null)
1048 				{
1049 					name = p.templateTupleParameter.identifier.text;
1050 					kind = CompletionKind.variadicTmpParam;
1051 					index = p.templateTupleParameter.identifier.index;
1052 				}
1053 				else
1054 					continue;
1055 				SemanticSymbol* templateParameter = allocateSemanticSymbol(name,
1056 					kind, symbolFile, index);
1057 				if (type !is null)
1058 					addTypeToLookups(templateParameter.typeLookups, type);
1059 
1060 				if (p.templateTupleParameter !is null)
1061 				{
1062 					TypeLookup* tl = TypeLookupsAllocator.instance.make!TypeLookup(
1063 						istring(name), TypeLookupKind.varOrFunType);
1064 					templateParameter.typeLookups.insert(tl);
1065 				}
1066 				else if (p.templateTypeParameter && kind == CompletionKind.typeTmpParam)
1067 				{
1068 					TypeLookup* tl = TypeLookupsAllocator.instance.make!TypeLookup(
1069 						istring(name), TypeLookupKind.varOrFunType);
1070 					templateParameter.typeLookups.insert(tl);
1071 				}
1072 
1073 				templateParameter.parent = symbol;
1074 				symbol.addChild(templateParameter, true);
1075 				if (currentScope)
1076 					currentScope.addSymbol(templateParameter.acSymbol, false);
1077 			}
1078 		}
1079 	}
1080 
1081 	istring formatCallTip(const Type returnType, string name,
1082 		const Parameters parameters, const TemplateParameters templateParameters)
1083 	{
1084 		import std.array : appender;
1085 
1086 		auto app = appender!string();
1087 		if (returnType !is null)
1088 		{
1089 			app.formatNode(returnType);
1090 			app.put(' ');
1091 		}
1092 		app.put(name);
1093 		if (templateParameters !is null)
1094 			app.formatNode(templateParameters);
1095 		if (parameters is null)
1096 			app.put("()");
1097 		else
1098 			app.formatNode(parameters);
1099 		return istring(app.data);
1100 	}
1101 
1102 	void populateInitializer(T)(SemanticSymbol* symbol, const T initializer,
1103 		bool appendForeach = false)
1104 	{
1105 		auto lookup = TypeLookupsAllocator.instance.make!TypeLookup(TypeLookupKind.initializer);
1106 		scope visitor = new InitializerVisitor(lookup, appendForeach, this);
1107 		symbol.typeLookups.insert(lookup);
1108 		visitor.visit(initializer);
1109 	}
1110 
1111 	SemanticSymbol* allocateSemanticSymbol(string name, CompletionKind kind,
1112 		istring symbolFile, size_t location = 0)
1113 	in
1114 	{
1115 		assert (symbolAllocator !is null);
1116 	}
1117 	do
1118 	{
1119 		DSymbol* acSymbol = SymbolAllocator.instance.make!DSymbol(istring(name), kind);
1120 		acSymbol.location = location;
1121 		acSymbol.symbolFile = symbolFile;
1122 		symbolsAllocated++;
1123 		return SymbolAllocator.instance.make!SemanticSymbol(acSymbol); // NOTE using semanticAllocator here breaks when analysing phobos as: `Segmentation fault (core dumped)‘’
1124 	}
1125 
1126 	void addTypeToLookups(ref TypeLookups lookups,
1127 		const Type type, TypeLookup* l = null)
1128 	{
1129 		auto lookup = l !is null ? l : TypeLookupsAllocator.instance.make!TypeLookup(
1130 			TypeLookupKind.varOrFunType);
1131 		auto t2 = type.type2;
1132 		if (t2.type !is null)
1133 			addTypeToLookups(lookups, t2.type, lookup);
1134 		else if (t2.superOrThis is tok!"this")
1135 			lookup.breadcrumbs.insert(internString("this"));
1136 		else if (t2.superOrThis is tok!"super")
1137 			lookup.breadcrumbs.insert(internString("super"));
1138 		else if (t2.builtinType !is tok!"")
1139 			lookup.breadcrumbs.insert(getBuiltinTypeName(t2.builtinType));
1140 		else if (t2.typeIdentifierPart !is null)
1141 			writeIotcTo(t2.typeIdentifierPart, lookup.breadcrumbs);
1142 		else
1143 		{
1144 			// TODO: Add support for typeof expressions
1145 			// TODO: Add support for __vector
1146 //			warning("typeof() and __vector are not yet supported");
1147 		}
1148 
1149 		foreach (suffix; type.typeSuffixes)
1150 		{
1151 			if (suffix.star != tok!"")
1152 				continue;
1153 			else if (suffix.type)
1154 				lookup.breadcrumbs.insert(ASSOC_ARRAY_SYMBOL_NAME);
1155 			else if (suffix.array)
1156 				lookup.breadcrumbs.insert(ARRAY_SYMBOL_NAME);
1157 			else if (suffix.star != tok!"")
1158 				lookup.breadcrumbs.insert(POINTER_SYMBOL_NAME);
1159 			else if (suffix.delegateOrFunction != tok!"")
1160 			{
1161 				import std.array : appender;
1162 				auto app = appender!string();
1163 				formatNode(app, type);
1164 				istring callTip = istring(app.data);
1165 				// Insert the call tip and THEN the "function" string because
1166 				// the breadcrumbs are processed in reverse order
1167 				lookup.breadcrumbs.insert(callTip);
1168 				lookup.breadcrumbs.insert(FUNCTION_SYMBOL_NAME);
1169 			}
1170 		}
1171 		if (l is null)
1172 			lookups.insert(lookup);
1173 	}
1174 
1175 	DocString makeDocumentation(string documentation)
1176 	{
1177 		if (documentation.isDitto)
1178 			return DocString(lastComment, true);
1179 		else
1180 		{
1181 			lastComment = internString(documentation);
1182 			return DocString(lastComment, false);
1183 		}
1184 	}
1185 
1186 	/// Current protection type
1187 	ProtectionStack protection;
1188 
1189 	/// Current scope
1190 	Scope* currentScope;
1191 
1192 	/// Current symbol
1193 	SemanticSymbol* currentSymbol;
1194 
1195 	/// Path to the file being converted
1196 	istring symbolFile;
1197 
1198 	/// Field types used for generating struct constructors if no constructor
1199 	/// was defined
1200 	// TODO: This should be `const Type`, but Rebindable and opEquals don't play
1201 	// well together
1202 	UnrolledList!(Type) structFieldTypes;
1203 
1204 	/// Field names for struct constructor generation
1205 	UnrolledList!(istring) structFieldNames;
1206 
1207 	/// Last comment for ditto-ing
1208 	istring lastComment;
1209 
1210 	const Module mod;
1211 
1212 	IAllocator semanticAllocator;
1213 
1214 	Rebindable!(const ExpressionNode) feExpression;
1215 
1216 	CacheEntry* entry;
1217 
1218 	ModuleCache* cache;
1219 
1220 	bool includeParameterSymbols;
1221 	bool skipBaseClassesOfNewAnon;
1222 
1223 	ubyte foreachTypeIndexOfInterest;
1224 	ubyte foreachTypeIndex;
1225 }
1226 
1227 struct ProtectionStack
1228 {
1229 	invariant
1230 	{
1231 		import std.algorithm.iteration : filter, joiner, map;
1232 		import std.conv:to;
1233 		import std.range : walkLength;
1234 
1235 		assert(stack.length == stack[].filter!(a => isProtection(a)
1236 				|| a == tok!":" || a == tok!"{").walkLength(), to!string(stack[].map!(a => str(a)).joiner(", ")));
1237 	}
1238 
1239 	IdType currentForImport() const
1240 	{
1241 		return stack.empty ? tok!"default" : current();
1242 	}
1243 
1244 	IdType current() const
1245 	{
1246 		import std.algorithm.iteration : filter;
1247 		import std.range : choose, only;
1248 
1249 		IdType retVal;
1250 		foreach (t; choose(stack.empty, only(tok!"public"), stack[]).filter!(
1251 				a => a != tok!"{" && a != tok!":"))
1252 			retVal = cast(IdType) t;
1253 		return retVal;
1254 	}
1255 
1256 	void beginScope()
1257 	{
1258 		stack.insertBack(tok!"{");
1259 	}
1260 
1261 	void endScope()
1262 	{
1263 		import std.algorithm.iteration : joiner;
1264 		import std.conv : to;
1265 		import std.range : walkLength;
1266 
1267 		while (!stack.empty && stack.back == tok!":")
1268 		{
1269 			assert(stack.length >= 2);
1270 			stack.popBack();
1271 			stack.popBack();
1272 		}
1273 		assert(stack.length == stack[].walkLength());
1274 		assert(!stack.empty && stack.back == tok!"{", to!string(stack[].map!(a => str(a)).joiner(", ")));
1275 		stack.popBack();
1276 	}
1277 
1278 	void beginLocal(const IdType t)
1279 	{
1280 		assert (t != tok!"", "DERP!");
1281 		stack.insertBack(t);
1282 	}
1283 
1284 	void endLocal()
1285 	{
1286 		import std.algorithm.iteration : joiner;
1287 		import std.conv : to;
1288 
1289 		assert(!stack.empty && stack.back != tok!":" && stack.back != tok!"{",
1290 				to!string(stack[].map!(a => str(a)).joiner(", ")));
1291 		stack.popBack();
1292 	}
1293 
1294 	void addScope(const IdType t)
1295 	{
1296 		assert(t != tok!"", "DERP!");
1297 		assert(isProtection(t));
1298 		if (!stack.empty && stack.back == tok!":")
1299 		{
1300 			assert(stack.length >= 2);
1301 			stack.popBack();
1302 			assert(isProtection(stack.back));
1303 			stack.popBack();
1304 		}
1305 		stack.insertBack(t);
1306 		stack.insertBack(tok!":");
1307 	}
1308 
1309 private:
1310 
1311 	UnrolledList!IdType stack;
1312 }
1313 
1314 void formatNode(A, T)(ref A appender, const T node)
1315 {
1316 	if (node is null)
1317 		return;
1318 	scope f = new Formatter!(A*)(&appender);
1319 	f.format(node);
1320 }
1321 
1322 private:
1323 
1324 bool isDitto(scope const(char)[] comment)
1325 {
1326 	import std.uni : icmp;
1327 
1328 	return comment.length == 5 && icmp(comment, "ditto") == 0;
1329 }
1330 
1331 void writeIotcTo(T)(const TypeIdentifierPart tip, ref T output) nothrow
1332 {
1333 	if (!tip.identifierOrTemplateInstance)
1334 		return;
1335 	if (tip.identifierOrTemplateInstance.identifier != tok!"")
1336 		output.insert(internString(tip.identifierOrTemplateInstance.identifier.text));
1337 	else
1338 		output.insert(internString(tip.identifierOrTemplateInstance.templateInstance.identifier.text));
1339 
1340 	// the indexer of a TypeIdentifierPart means either that there's
1341 	// a static array dimension or that a type is selected in a type list.
1342 	// we can only handle the first case since dsymbol does not process templates yet.
1343 	if (tip.indexer)
1344 		output.insert(ARRAY_SYMBOL_NAME);
1345 
1346 	if (tip.typeIdentifierPart)
1347 		writeIotcTo(tip.typeIdentifierPart, output);
1348 }
1349 
1350 auto byIdentifier(const IdentifierOrTemplateChain iotc) nothrow
1351 {
1352 	import std.algorithm : map;
1353 
1354 	return iotc.identifiersOrTemplateInstances.map!(a => a.identifier == tok!""
1355 		? a.templateInstance.identifier.text
1356 		: a.identifier.text);
1357 }
1358 
1359 void writeIotcTo(T)(const IdentifierOrTemplateChain iotc, ref T output) nothrow
1360 {
1361 	import std.algorithm : each;
1362 
1363 	byIdentifier(iotc).each!(a => output.insert(internString(a)));
1364 }
1365 
1366 static istring convertChainToImportPath(const IdentifierChain ic)
1367 {
1368 	import std.path : dirSeparator;
1369 	import std.array : appender;
1370 	auto app = appender!string();
1371 	foreach (i, ident; ic.identifiers)
1372 	{
1373 		app.put(ident.text);
1374 		if (i + 1 < ic.identifiers.length)
1375 			app.put(dirSeparator);
1376 	}
1377 	return istring(app.data);
1378 }
1379 
1380 class InitializerVisitor : ASTVisitor
1381 {
1382 	this (TypeLookup* lookup, bool appendForeach, FirstPass fp)
1383 	{
1384 		this.lookup = lookup;
1385 		this.appendForeach = appendForeach;
1386 		this.fp = fp;
1387 	}
1388 
1389 	alias visit = ASTVisitor.visit;
1390 
1391 	override void visit(const FunctionLiteralExpression exp)
1392 	{
1393 		fp.visit(exp);
1394 	}
1395 
1396 	override void visit(const IdentifierOrTemplateInstance ioti)
1397 	{
1398 		if (on && ioti.identifier != tok!"")
1399 			lookup.breadcrumbs.insert(internString(ioti.identifier.text));
1400 		else if (on && ioti.templateInstance.identifier != tok!"")
1401 			lookup.breadcrumbs.insert(internString(ioti.templateInstance.identifier.text));
1402 		ioti.accept(this);
1403 	}
1404 
1405 	override void visit(const PrimaryExpression primary)
1406 	{
1407 		// Add identifiers without processing. Convert literals to strings with
1408 		// the prefix '*' so that that the second pass can tell the difference
1409 		// between "int.abc" and "10.abc".
1410 		if (on && primary.basicType != tok!"")
1411 			lookup.breadcrumbs.insert(internString(str(primary.basicType.type)));
1412 		if (on) switch (primary.primary.type)
1413 		{
1414 		case tok!"identifier":
1415 			lookup.breadcrumbs.insert(internString(primary.primary.text));
1416 			break;
1417 		case tok!"doubleLiteral":
1418 			lookup.breadcrumbs.insert(DOUBLE_LITERAL_SYMBOL_NAME);
1419 			break;
1420 		case tok!"floatLiteral":
1421 			lookup.breadcrumbs.insert(FLOAT_LITERAL_SYMBOL_NAME);
1422 			break;
1423 		case tok!"idoubleLiteral":
1424 			lookup.breadcrumbs.insert(IDOUBLE_LITERAL_SYMBOL_NAME);
1425 			break;
1426 		case tok!"ifloatLiteral":
1427 			lookup.breadcrumbs.insert(IFLOAT_LITERAL_SYMBOL_NAME);
1428 			break;
1429 		case tok!"intLiteral":
1430 			lookup.breadcrumbs.insert(INT_LITERAL_SYMBOL_NAME);
1431 			break;
1432 		case tok!"longLiteral":
1433 			lookup.breadcrumbs.insert(LONG_LITERAL_SYMBOL_NAME);
1434 			break;
1435 		case tok!"realLiteral":
1436 			lookup.breadcrumbs.insert(REAL_LITERAL_SYMBOL_NAME);
1437 			break;
1438 		case tok!"irealLiteral":
1439 			lookup.breadcrumbs.insert(IREAL_LITERAL_SYMBOL_NAME);
1440 			break;
1441 		case tok!"uintLiteral":
1442 			lookup.breadcrumbs.insert(UINT_LITERAL_SYMBOL_NAME);
1443 			break;
1444 		case tok!"ulongLiteral":
1445 			lookup.breadcrumbs.insert(ULONG_LITERAL_SYMBOL_NAME);
1446 			break;
1447 		case tok!"characterLiteral":
1448 			lookup.breadcrumbs.insert(CHAR_LITERAL_SYMBOL_NAME);
1449 			break;
1450 		case tok!"dstringLiteral":
1451 			lookup.breadcrumbs.insert(DSTRING_LITERAL_SYMBOL_NAME);
1452 			break;
1453 		case tok!"stringLiteral":
1454 			lookup.breadcrumbs.insert(STRING_LITERAL_SYMBOL_NAME);
1455 			break;
1456 		case tok!"wstringLiteral":
1457 			lookup.breadcrumbs.insert(WSTRING_LITERAL_SYMBOL_NAME);
1458 			break;
1459 		case tok!"false":
1460 		case tok!"true":
1461 			lookup.breadcrumbs.insert(BOOL_VALUE_SYMBOL_NAME);
1462 			break;
1463 		default:
1464 			break;
1465 		}
1466 		primary.accept(this);
1467 	}
1468 
1469 	override void visit(const IndexExpression expr)
1470 	{
1471 		expr.unaryExpression.accept(this);
1472 		foreach (index; expr.indexes)
1473 			if (index.high is null)
1474 				lookup.breadcrumbs.insert(ARRAY_SYMBOL_NAME);
1475 	}
1476 
1477 	override void visit(const Initializer initializer)
1478 	{
1479 		on = true;
1480 		initializer.accept(this);
1481 		on = false;
1482 	}
1483 
1484 	override void visit(const ArrayInitializer ai)
1485 	{
1486 		// If the array has any elements, assume all elements have the
1487 		// same type as the first element.
1488 		if (ai.arrayMemberInitializations.length)
1489 			ai.arrayMemberInitializations[0].accept(this);
1490 		else
1491 			lookup.breadcrumbs.insert(VOID_SYMBOL_NAME);
1492 
1493 		lookup.breadcrumbs.insert(ARRAY_LITERAL_SYMBOL_NAME);
1494 	}
1495 
1496 	override void visit(const ArrayLiteral al)
1497 	{
1498 		// ditto
1499 		if (al.argumentList)
1500 		{
1501 			if (al.argumentList.items.length)
1502 				al.argumentList.items[0].accept(this);
1503 			else
1504 				lookup.breadcrumbs.insert(VOID_SYMBOL_NAME);
1505 		}
1506 		lookup.breadcrumbs.insert(ARRAY_LITERAL_SYMBOL_NAME);
1507 	}
1508 
1509 	// Skip it
1510 	override void visit(const NewAnonClassExpression) {}
1511 
1512 	override void visit(const NewExpression ne)
1513 	{
1514 		if (ne.newAnonClassExpression)
1515 			lowerNewAnonToNew((cast() ne));
1516 		ne.accept(this);
1517 	}
1518 
1519 	private void lowerNewAnonToNew(NewExpression ne)
1520 	{
1521 		import std.format : format;
1522 
1523 		// here we follow DMDFE naming style
1524 		__gshared size_t anonIndex;
1525 		const idt = istring("__anonclass%d".format(++anonIndex));
1526 
1527 		// the goal is to replace it so we null the field
1528 		NewAnonClassExpression nace = ne.newAnonClassExpression;
1529 		ne.newAnonClassExpression = null;
1530 
1531 		// Lower the AnonClass body to a standard ClassDeclaration and visit it.
1532 		ClassDeclaration cd = theAllocator.make!(ClassDeclaration);
1533 		cd.name = Token(tok!"identifier", idt, 1, 1, nace.structBody.startLocation - idt.length);
1534 		cd.baseClassList = nace.baseClassList;
1535 		cd.structBody = nace.structBody;
1536 		fp.visit(cd);
1537 
1538 		// Change the NewAnonClassExpression to a standard NewExpression using
1539 		// the ClassDeclaration created in previous step
1540 		ne.type = theAllocator.make!(Type);
1541 		ne.type.type2 = theAllocator.make!(Type2);
1542 		ne.type.type2.typeIdentifierPart = theAllocator.make!(TypeIdentifierPart);
1543 		ne.type.type2.typeIdentifierPart.identifierOrTemplateInstance = theAllocator.make!(IdentifierOrTemplateInstance);
1544 		ne.type.type2.typeIdentifierPart.identifierOrTemplateInstance.identifier = cd.name;
1545 		ne.arguments = nace.constructorArguments;
1546 	}
1547 
1548 	override void visit(const ArgumentList list)
1549 	{
1550 		scope visitor = new ArgumentListVisitor(fp);
1551 		visitor.visit(list);
1552 	}
1553 
1554 	override void visit(const Expression expression)
1555 	{
1556 		on = true;
1557 		expression.accept(this);
1558 		if (appendForeach)
1559 			lookup.breadcrumbs.insert(internString("foreach"));
1560 		on = false;
1561 	}
1562 
1563 	override void visit(const ExpressionNode expression)
1564 	{
1565 		on = true;
1566 		expression.accept(this);
1567 		if (appendForeach)
1568 			lookup.breadcrumbs.insert(internString("foreach"));
1569 		on = false;
1570 	}
1571 
1572 	TypeLookup* lookup;
1573 	bool on = false;
1574 	const bool appendForeach;
1575 	FirstPass fp;
1576 }
1577 
1578 class ArgumentListVisitor : ASTVisitor
1579 {
1580 	this(FirstPass fp)
1581 	{
1582 		assert(fp);
1583 		this.fp = fp;
1584 	}
1585 
1586 	alias visit = ASTVisitor.visit;
1587 
1588 	override void visit(const FunctionLiteralExpression exp)
1589 	{
1590 		fp.visit(exp);
1591 	}
1592 
1593 	override void visit(const NewAnonClassExpression exp)
1594 	{
1595 		fp.visit(exp);
1596 	}
1597 
1598 private:
1599 	FirstPass fp;
1600 }