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