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