diff --git a/.gitignore b/.gitignore
index c994c34..686f415 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,8 +5,10 @@
 # *nix binaries
 dcd-client
 dcd-server
-dcd-client.o
-dcd-server.o
+*.o
 
 # Perf reports
 perf.data
+
+# Valgrind reports
+callgrind.*
diff --git a/actypes.d b/actypes.d
index a911411..c64752c 100644
--- a/actypes.d
+++ b/actypes.d
@@ -1,6 +1,6 @@
 /**
  * This file is part of DCD, a development tool for the D programming language.
- * Copyright (C) 2013 Brian Schott
+ * Copyright (C) 2014 Brian Schott
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -28,6 +28,9 @@ import std.array;
 import std.typecons;
 import std.container;
 
+/**
+ * Compares symbols by their name
+ */
 bool comparitor(const(ACSymbol)* a, const(ACSymbol)* b) pure nothrow
 {
 	return a.name < b.name;
@@ -150,8 +153,16 @@ public:
 	SymbolQualifier qualifier;
 }
 
+/**
+ * Contains symbols and supports lookup of symbols by cursor position.
+ */
 struct Scope
 {
+	/**
+	 * Params:
+	 *     begin = the beginning byte index
+	 *     end = the ending byte index
+	 */
 	this (size_t begin, size_t end)
 	{
 		this.startLocation = begin;
@@ -159,6 +170,12 @@ struct Scope
 		this.symbols = new RedBlackTree!(ACSymbol*, comparitor, true);
 	}
 
+	/**
+	 * Params:
+	 *     cursorPosition = the cursor position in bytes
+	 * Returns:
+	 *     the innermost scope that contains the given cursor position
+	 */
 	Scope* getScopeByCursor(size_t cursorPosition) const
 	{
 		if (cursorPosition < startLocation) return null;
@@ -172,6 +189,13 @@ struct Scope
 		return cast(typeof(return)) &this;
 	}
 
+	/**
+	 * Params:
+	 *     cursorPosition = the cursor position in bytes
+	 * Returns:
+	 *     all symbols in the scope containing the cursor position, as well as
+	 *     the symbols in parent scopes of that scope.
+	 */
 	ACSymbol*[] getSymbolsInCursorScope(size_t cursorPosition) const
 	{
 		auto s = getScopeByCursor(cursorPosition);
@@ -188,14 +212,18 @@ struct Scope
 		return symbols.array();
 	}
 
+	/**
+	 * Params:
+	 *     name = the symbol name to search for
+	 * Returns:
+	 *     all symbols in this scope or parent scopes with the given name
+	 */
 	ACSymbol*[] getSymbolsByName(string name) const
 	{
 		import std.range;
 		ACSymbol s = ACSymbol(name);
 		RedBlackTree!(ACSymbol*, comparitor, true) t = cast() symbols;
 		auto r = t.equalRange(&s).array();
-		version(assert) foreach (n; r)
-			assert (n.name == name, name);
 		if (r.length > 0)
 			return cast(typeof(return)) r;
 		if (parent is null)
@@ -203,6 +231,14 @@ struct Scope
 		return parent.getSymbolsByName(name);
 	}
 
+	/**
+	 * Params:
+	 *     name = the symbol name to search for
+	 *     cursorPosition = the cursor position in bytes
+	 * Returns:
+	 *     all symbols with the given name in the scope containing the cursor
+	 *     and its parent scopes
+	 */
 	ACSymbol*[] getSymbolsByNameAndCursor(string name, size_t cursorPosition) const
 	{
 		auto s = getScopeByCursor(cursorPosition);
@@ -230,6 +266,9 @@ struct Scope
 	RedBlackTree!(ACSymbol*, comparitor, true) symbols;
 }
 
+/**
+ * Import information
+ */
 struct ImportInformation
 {
 	/// Import statement parts
@@ -243,6 +282,41 @@ struct ImportInformation
 }
 
 
+/**
+ * Symbols for the built in types
+ */
+RedBlackTree!(ACSymbol*, comparitor, true) builtinSymbols;
+
+/**
+ * Array properties
+ */
+RedBlackTree!(ACSymbol*, comparitor, true) arraySymbols;
+
+/**
+ * Associative array properties
+ */
+RedBlackTree!(ACSymbol*, comparitor, true) assocArraySymbols;
+
+/**
+ * Enum, union, class, and interface properties
+ */
+RedBlackTree!(ACSymbol*, comparitor, true) aggregateSymbols;
+
+/**
+ * Class properties
+ */
+RedBlackTree!(ACSymbol*, comparitor, true) classSymbols;
+
+/**
+ * Type of the _argptr variable
+ */
+Type argptrType;
+
+/**
+ * Type of _arguments
+ */
+Type argumentsType;
+
 /**
  * Initializes builtin types and the various properties of builtin types
  */
@@ -406,10 +480,3 @@ static this()
 	classSymbols = clSym;
 }
 
-RedBlackTree!(ACSymbol*, comparitor, true) builtinSymbols;
-RedBlackTree!(ACSymbol*, comparitor, true) arraySymbols;
-RedBlackTree!(ACSymbol*, comparitor, true) assocArraySymbols;
-RedBlackTree!(ACSymbol*, comparitor, true) aggregateSymbols;
-RedBlackTree!(ACSymbol*, comparitor, true) classSymbols;
-Type argptrType;
-Type argumentsType;
diff --git a/astconverter.d b/astconverter.d
index f82a10d..f8cff2a 100644
--- a/astconverter.d
+++ b/astconverter.d
@@ -1,9 +1,7 @@
-/*******************************************************************************
- * Authors: Brian Schott
- * Copyright: Brian Schott
- * Date: Sep 21 2013
+/**
+ * This file is part of DCD, a development tool for the D programming language.
+ * Copyright (C) 2014 Brian Schott
  *
- * License:
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
@@ -16,7 +14,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- ******************************************************************************/
+ */
 
 module astconverter;
 
diff --git a/autocomplete.d b/autocomplete.d
index 571cb8e..574bdc0 100644
--- a/autocomplete.d
+++ b/autocomplete.d
@@ -1,9 +1,7 @@
-/*******************************************************************************
- * Authors: Brian Schott
- * Copyright: Brian Schott
- * Date: Jul 19 2013
+/**
+ * This file is part of DCD, a development tool for the D programming language.
+ * Copyright (C) 2014 Brian Schott
  *
- * License:
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
@@ -16,7 +14,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- ******************************************************************************/
+ */
 
 module autocomplete;
 
@@ -40,35 +38,18 @@ import modulecache;
 import astconverter;
 import stupidlog;
 
+/**
+ * Gets documentation for the symbol at the cursor
+ * Params:
+ *     request = the autocompletion request
+ * Returns:
+ *     the autocompletion response
+ */
 AutocompleteResponse getDoc(const AutocompleteRequest request)
 {
 	Log.trace("Getting doc comments");
-
 	AutocompleteResponse response;
-	LexerConfig config;
-	config.fileName = "stdin";
-	StringCache* cache = new StringCache(StringCache.defaultBucketCount);
-	auto tokens = byToken(cast(ubyte[]) request.sourceCode, config, cache);
-	const(Token)[] tokenArray = void;
-	try {
-		tokenArray = tokens.array();
-	} catch (Exception e) {
-		Log.error("Could not provide autocomplete due to lexing exception: ", e.msg);
-		return response;
-	}
-	auto sortedTokens = assumeSorted(tokenArray);
-	string partial;
-
-	auto beforeTokens = sortedTokens.lowerBound(cast(size_t) request.cursorPosition);
-
-	Log.trace("Token at cursor: ", beforeTokens[$ - 1].text);
-
-	const(Scope)* completionScope = generateAutocompleteTrees(tokenArray, "stdin");
-	auto expression = getExpression(beforeTokens);
-
-	ACSymbol*[] symbols = getSymbolsByTokenChain(completionScope, expression,
-		request.cursorPosition, CompletionType.ddoc);
-
+	ACSymbol*[] symbols = getSymbolsForCompletion(request, CompletionType.ddoc);
 	if (symbols.length == 0)
 		Log.error("Could not find symbol");
 	else foreach (symbol; symbols)
@@ -86,76 +67,213 @@ AutocompleteResponse getDoc(const AutocompleteRequest request)
 
 /**
  * Finds the declaration of the symbol at the cursor position.
+ * Params:
+ *     request = the autocompletion request
+ * Returns:
+ *     the autocompletion response
  */
 AutocompleteResponse findDeclaration(const AutocompleteRequest request)
 {
 	Log.trace("Finding declaration");
 	AutocompleteResponse response;
-	LexerConfig config;
-	config.fileName = "stdin";
-	StringCache* cache = new StringCache(StringCache.defaultBucketCount);
-	auto tokens = byToken(cast(ubyte[]) request.sourceCode, config, cache);
-	const(Token)[] tokenArray = void;
-	try {
-		tokenArray = tokens.array();
-	} catch (Exception e) {
-		Log.error("Could not provide autocomplete due to lexing exception: ", e.msg);
-		return response;
-	}
-	auto sortedTokens = assumeSorted(tokenArray);
-	string partial;
-
-	auto beforeTokens = sortedTokens.lowerBound(cast(size_t) request.cursorPosition);
-
-	Log.trace("Token at cursor: ", beforeTokens[$ - 1].text);
-
-	const(Scope)* completionScope = generateAutocompleteTrees(tokenArray, "stdin");
-	auto expression = getExpression(beforeTokens);
-
-	ACSymbol*[] symbols = getSymbolsByTokenChain(completionScope, expression,
-		request.cursorPosition, CompletionType.location);
-
+	ACSymbol*[] symbols = getSymbolsForCompletion(request, CompletionType.location);
 	if (symbols.length > 0)
 	{
 		response.symbolLocation = symbols[0].location;
 		response.symbolFilePath = symbols[0].symbolFile;
-		Log.info(beforeTokens[$ - 1].text, " declared in ",
+		Log.info(symbols[0].name, " declared in ",
 			response.symbolFilePath, " at ", response.symbolLocation);
 	}
 	else
-	{
 		Log.error("Could not find symbol");
-	}
-
 	return response;
 }
 
-bool shouldSwapWithType(CompletionType completionType, CompletionKind kind,
-	size_t current, size_t max) pure nothrow @safe
+/**
+ * Handles autocompletion
+ * Params:
+ *     request = the autocompletion request
+ * Returns:
+ *     the autocompletion response
+ */
+AutocompleteResponse complete(const AutocompleteRequest request)
 {
-	// Modules and packages never have types, so always return false
-	if (kind == CompletionKind.moduleName
-		|| kind == CompletionKind.packageName
-		|| kind == CompletionKind.className
-		|| kind == CompletionKind.structName
-		|| kind == CompletionKind.interfaceName
-		|| kind == CompletionKind.enumName
-		|| kind == CompletionKind.unionName)
+	Log.info("Got a completion request");
+
+	const(Token)[] tokenArray;
+	auto beforeTokens = getTokensBeforeCursor(request.sourceCode,
+		request.cursorPosition, tokenArray);
+	string partial;
+	IdType tokenType;
+
+	if (beforeTokens.length >= 2 && beforeTokens[$ - 1] == tok!"(")
+		return parenCompletion(beforeTokens, tokenArray, request.cursorPosition);
+
+	AutocompleteResponse response;
+	if (beforeTokens.length >= 1 && beforeTokens[$ - 1] == tok!"identifier")
 	{
-		return false;
+		partial = beforeTokens[$ - 1].text;
+		tokenType = beforeTokens[$ - 1].type;
+		beforeTokens = beforeTokens[0 .. $ - 1];
 	}
-	// Swap out every part of a chain with its type except the last part
-	if (current < max)
-		return true;
-	// Only swap out types for these kinds
-	immutable bool isInteresting =
-		kind == CompletionKind.variableName
-		|| kind == CompletionKind.memberVariableName
-		|| kind == CompletionKind.enumMember
-		|| kind == CompletionKind.functionName;
-	return completionType == CompletionType.identifiers && isInteresting;
+	else if (beforeTokens.length >= 2 && beforeTokens[$ - 1] ==  tok!".")
+		tokenType = beforeTokens[$ - 2].type;
+	else
+		return response;
+
+	switch (tokenType)
+	{
+	case tok!"stringLiteral":
+	case tok!"wstringLiteral":
+	case tok!"dstringLiteral":
+		foreach (symbol; (cast() arraySymbols)[])
+		{
+			response.completionKinds ~= symbol.kind;
+			response.completions ~= symbol.name;
+		}
+		response.completionType = CompletionType.identifiers;
+		break;
+	case tok!"int":
+	case tok!"uint":
+	case tok!"long":
+	case tok!"ulong":
+	case tok!"char":
+	case tok!"wchar":
+	case tok!"dchar":
+	case tok!"bool":
+	case tok!"byte":
+	case tok!"ubyte":
+	case tok!"short":
+	case tok!"ushort":
+	case tok!"cent":
+	case tok!"ucent":
+	case tok!"float":
+	case tok!"ifloat":
+	case tok!"cfloat":
+	case tok!"idouble":
+	case tok!"cdouble":
+	case tok!"double":
+	case tok!"real":
+	case tok!"ireal":
+	case tok!"creal":
+	case tok!"identifier":
+	case tok!")":
+	case tok!"]":
+	case tok!"this":
+		const(Scope)* completionScope = generateAutocompleteTrees(tokenArray,
+			"stdin");
+		auto expression = getExpression(beforeTokens);
+		response.setCompletions(completionScope, expression,
+			request.cursorPosition, CompletionType.identifiers, partial);
+		break;
+	case tok!"(":
+	case tok!"{":
+	case tok!"[":
+	case tok!";":
+	case tok!":":
+		// TODO: global scope
+		break;
+	default:
+		break;
+	}
+	return response;
 }
 
+/**
+ * Params:
+ *     sourceCode = the source code of the file being edited
+ *     cursorPosition = the cursor position in bytes
+ * Returns:
+ *     a sorted range of tokens before the cursor position
+ */
+auto getTokensBeforeCursor(const(ubyte[]) sourceCode, size_t cursorPosition,
+	out const(Token)[] tokenArray)
+{
+	LexerConfig config;
+	config.fileName = "stdin";
+	StringCache* cache = new StringCache(StringCache.defaultBucketCount);
+	auto tokens = byToken(cast(ubyte[]) sourceCode, config, cache);
+	tokenArray = tokens.array();
+	auto sortedTokens = assumeSorted(tokenArray);
+	return sortedTokens.lowerBound(cast(size_t) cursorPosition);
+}
+
+/**
+ * Params:
+ *     request = the autocompletion request
+ *     type = type the autocompletion type
+ * Returns:
+ *     all symbols that should be considered for the autocomplete list based on
+ *     the request's source code, cursor position, and completion type.
+ */
+ACSymbol*[] getSymbolsForCompletion(const AutocompleteRequest request,
+	const CompletionType type)
+{
+	const(Token)[] tokenArray;
+	auto beforeTokens = getTokensBeforeCursor(request.sourceCode,
+		request.cursorPosition, tokenArray);
+	const(Scope)* completionScope = generateAutocompleteTrees(tokenArray, "stdin");
+	auto expression = getExpression(beforeTokens);
+	return getSymbolsByTokenChain(completionScope, expression,
+		request.cursorPosition, type);
+}
+
+/**
+ * Handles paren completion for function calls and some keywords
+ * Params:
+ *     beforeTokens = the tokens before the cursor
+ *     tokenArray = all tokens in the file
+ *     cursorPosition = the cursor position in bytes
+ * Returns:
+ *     the autocompletion response
+ */
+AutocompleteResponse parenCompletion(T)(T beforeTokens,
+	const(Token)[] tokenArray, size_t cursorPosition)
+{
+	AutocompleteResponse response;
+	immutable(string)[] completions;
+	switch (beforeTokens[$ - 2].type)
+	{
+	case tok!"__traits":
+		completions = traits;
+		goto fillResponse;
+	case tok!"scope":
+		completions = scopes;
+		goto fillResponse;
+	case tok!"version":
+		completions = versions;
+		goto fillResponse;
+	case tok!"extern":
+		completions = linkages;
+		goto fillResponse;
+	case tok!"pragma":
+		completions = pragmas;
+	fillResponse:
+		response.completionType = CompletionType.identifiers;
+		for (size_t i = 0; i < completions.length; i++)
+		{
+			response.completions ~= completions[i];
+			response.completionKinds ~= CompletionKind.keyword;
+		}
+		break;
+	case tok!"identifier":
+	case tok!")":
+	case tok!"]":
+		const(Scope)* completionScope = generateAutocompleteTrees(tokenArray,
+			"stdin");
+		auto expression = getExpression(beforeTokens[0 .. $ - 1]);
+		response.setCompletions(completionScope, expression,
+			cursorPosition, CompletionType.calltips);
+		break;
+	default:
+		break;
+	}
+	return response;
+}
+
+/**
+ *
+ */
 ACSymbol*[] getSymbolsByTokenChain(T)(const(Scope)* completionScope,
 	T tokens, size_t cursorPosition, CompletionType completionType)
 {
@@ -315,140 +433,9 @@ ACSymbol*[] getSymbolsByTokenChain(T)(const(Scope)* completionScope,
 	return symbols;
 }
 
-AutocompleteResponse complete(const AutocompleteRequest request)
-{
-	Log.info("Got a completion request");
-	AutocompleteResponse response;
-
-	LexerConfig config;
-	config.fileName = "stdin";
-	StringCache* cache = new StringCache(StringCache.defaultBucketCount);
-	auto tokens = byToken(cast(ubyte[]) request.sourceCode, config,
-		cache);
-	const(Token)[] tokenArray = void;
-	try {
-		tokenArray = tokens.array();
-	} catch (Exception e) {
-		Log.error("Could not provide autocomplete due to lexing exception: ", e.msg);
-		return response;
-	}
-	auto sortedTokens = assumeSorted(tokenArray);
-	string partial;
-
-	auto beforeTokens = sortedTokens.lowerBound(cast(size_t) request.cursorPosition);
-
-	IdType tokenType;
-
-	if (beforeTokens.length >= 1 && beforeTokens[$ - 1] == tok!"identifier")
-	{
-		partial = beforeTokens[$ - 1].text;
-		tokenType = beforeTokens[$ - 1].type;
-		beforeTokens = beforeTokens[0 .. $ - 1];
-		goto dotCompletion;
-	}
-	else if (beforeTokens.length >= 2 && beforeTokens[$ - 1] == tok!"(")
-	{
-		immutable(string)[] completions;
-		switch (beforeTokens[$ - 2].type)
-		{
-		case tok!"__traits":
-			completions = traits;
-			goto fillResponse;
-		case tok!"scope":
-			completions = scopes;
-			goto fillResponse;
-		case tok!"version":
-			completions = versions;
-			goto fillResponse;
-		case tok!"extern":
-			completions = linkages;
-			goto fillResponse;
-		case tok!"pragma":
-			completions = pragmas;
-		fillResponse:
-			response.completionType = CompletionType.identifiers;
-			for (size_t i = 0; i < completions.length; i++)
-			{
-				response.completions ~= completions[i];
-				response.completionKinds ~= CompletionKind.keyword;
-			}
-			break;
-		case tok!"identifier":
-		case tok!")":
-		case tok!"]":
-			const(Scope)* completionScope = generateAutocompleteTrees(tokenArray,
-				"stdin");
-			auto expression = getExpression(beforeTokens[0 .. $ - 1]);
-			response.setCompletions(completionScope, expression,
-				request.cursorPosition, CompletionType.calltips);
-			break;
-		default:
-			break;
-		}
-	}
-	else if (beforeTokens.length >= 2 && beforeTokens[$ - 1] ==  tok!".")
-	{
-		tokenType = beforeTokens[$ - 2].type;
-dotCompletion:
-		switch (tokenType)
-		{
-		case tok!"stringLiteral":
-		case tok!"wstringLiteral":
-		case tok!"dstringLiteral":
-			foreach (symbol; (cast() arraySymbols)[])
-			{
-				response.completionKinds ~= symbol.kind;
-				response.completions ~= symbol.name;
-			}
-			response.completionType = CompletionType.identifiers;
-			break;
-		case tok!"int":
-		case tok!"uint":
-		case tok!"long":
-		case tok!"ulong":
-		case tok!"char":
-		case tok!"wchar":
-		case tok!"dchar":
-		case tok!"bool":
-		case tok!"byte":
-		case tok!"ubyte":
-		case tok!"short":
-		case tok!"ushort":
-		case tok!"cent":
-		case tok!"ucent":
-		case tok!"float":
-		case tok!"ifloat":
-		case tok!"cfloat":
-		case tok!"idouble":
-		case tok!"cdouble":
-		case tok!"double":
-		case tok!"real":
-		case tok!"ireal":
-		case tok!"creal":
-		case tok!"identifier":
-		case tok!")":
-		case tok!"]":
-		case tok!"this":
-			const(Scope)* completionScope = generateAutocompleteTrees(tokenArray,
-				"stdin");
-			auto expression = getExpression(beforeTokens);
-			response.setCompletions(completionScope, expression,
-				request.cursorPosition, CompletionType.identifiers, partial);
-			break;
-		case tok!"(":
-		case tok!"{":
-		case tok!"[":
-		case tok!";":
-		case tok!":":
-			// TODO: global scope
-			break;
-		default:
-			break;
-		}
-	}
-	return response;
-}
-
+/**
+ *
+ */
 void setCompletions(T)(ref AutocompleteResponse response,
 	const(Scope)* completionScope, T tokens, size_t cursorPosition,
 	CompletionType completionType, string partial = null)
@@ -538,6 +525,9 @@ void setCompletions(T)(ref AutocompleteResponse response,
 	}
 }
 
+/**
+ *
+ */
 T getExpression(T)(T beforeTokens)
 {
 	if (beforeTokens.length == 0)
@@ -641,6 +631,12 @@ T getExpression(T)(T beforeTokens)
 	return beforeTokens[i .. $];
 }
 
+/**
+ * Populates the response with completion information for an import statement
+ * Params:
+ *     tokens = the tokens after the "import" keyword and before the cursor
+ *     response = the response that should be populated
+ */
 void setImportCompletions(T)(T tokens, ref AutocompleteResponse response)
 {
 	response.completionType = CompletionType.identifiers;
@@ -650,7 +646,7 @@ void setImportCompletions(T)(T tokens, ref AutocompleteResponse response)
 	string path = buildPath(moduleParts);
 	foreach (importDirectory; ModuleCache.getImportPaths())
 	{
-		string p = format("%s%s%s", importDirectory, dirSeparator, path);
+		string p = buildPath(importDirectory, path);
 		Log.trace("Checking for ", p);
 		if (!exists(p))
 			continue;
@@ -672,6 +668,47 @@ void setImportCompletions(T)(T tokens, ref AutocompleteResponse response)
 	}
 }
 
+/**
+ * Params:
+ *     completionType = the completion type being requested
+ *     kind = the kind of the current item in the completion chain
+ *     current = the index of the current item in the symbol chain
+ *     max = the number of items in the symbol chain
+ * Returns:
+ *     true if the symbol should be swapped with its type field
+ */
+bool shouldSwapWithType(CompletionType completionType, CompletionKind kind,
+	size_t current, size_t max) pure nothrow @safe
+{
+	// Modules and packages never have types, so always return false
+	if (kind == CompletionKind.moduleName
+		|| kind == CompletionKind.packageName
+		|| kind == CompletionKind.className
+		|| kind == CompletionKind.structName
+		|| kind == CompletionKind.interfaceName
+		|| kind == CompletionKind.enumName
+		|| kind == CompletionKind.unionName)
+	{
+		return false;
+	}
+	// Swap out every part of a chain with its type except the last part
+	if (current < max)
+		return true;
+	// Only swap out types for these kinds
+	immutable bool isInteresting =
+		kind == CompletionKind.variableName
+		|| kind == CompletionKind.memberVariableName
+		|| kind == CompletionKind.enumMember
+		|| kind == CompletionKind.functionName;
+	return completionType == CompletionType.identifiers && isInteresting;
+}
+
+/**
+ * Params:
+ *     comment = the comment to format
+ * Returns
+ *     the comment with the comment characters removed
+ */
 string formatComment(string comment)
 {
 	import std.string;
diff --git a/client.d b/client.d
index 417e469..19ff945 100644
--- a/client.d
+++ b/client.d
@@ -1,6 +1,6 @@
 /**
  * This file is part of DCD, a development tool for the D programming language.
- * Copyright (C) 2013 Brian Schott
+ * Copyright (C) 2014 Brian Schott
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/constants.d b/constants.d
index d7b4f37..cb7c102 100644
--- a/constants.d
+++ b/constants.d
@@ -1,6 +1,6 @@
 /**
  * This file is part of DCD, a development tool for the D programming language.
- * Copyright (C) 2013 Brian Schott
+ * Copyright (C) 2014 Brian Schott
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/messages.d b/messages.d
index 2404e21..841b71d 100644
--- a/messages.d
+++ b/messages.d
@@ -1,6 +1,6 @@
 /**
  * This file is part of DCD, a development tool for the D programming language.
- * Copyright (C) 2013 Brian Schott
+ * Copyright (C) 2014 Brian Schott
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/modulecache.d b/modulecache.d
index 8068fbc..9913735 100644
--- a/modulecache.d
+++ b/modulecache.d
@@ -1,6 +1,6 @@
 /**
  * This file is part of DCD, a development tool for the D programming language.
- * Copyright (C) 2013 Brian Schott
+ * Copyright (C) 2014 Brian Schott
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/semantic.d b/semantic.d
index 0dfbab1..93c8a17 100644
--- a/semantic.d
+++ b/semantic.d
@@ -1,6 +1,6 @@
 /**
  * This file is part of DCD, a development tool for the D programming language.
- * Copyright (C) 2013 Brian Schott
+ * Copyright (C) 2014 Brian Schott
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -34,6 +34,13 @@ public:
 
 	@disable this();
 
+	/**
+	 * Params:
+	 *    name = the name
+	 *    kind = the completion kind
+	 *    symbolFile = the file name for this symbol
+	 *    location = the location of this symbol
+	 */
 	this(string name, CompletionKind kind, string symbolFile,
 		size_t location = size_t.max)
 	{
@@ -42,6 +49,9 @@ public:
 		acSymbol.symbolFile = symbolFile;
 	}
 
+	/**
+	 * Adds a child to the children field and updates the acSymbol's parts field
+	 */
 	void addChild(SemanticSymbol* child)
 	{
 		children ~= child;
@@ -66,7 +76,9 @@ public:
 	/// Protection level for this symobol
 	IdType protection;
 
+	/// Parent symbol
 	SemanticSymbol* parent;
 
+	/// Child symbols
 	SemanticSymbol*[] children;
 }
diff --git a/server.d b/server.d
index 4bc8185..1e95c82 100644
--- a/server.d
+++ b/server.d
@@ -1,6 +1,6 @@
 /**
  * This file is part of DCD, a development tool for the D programming language.
- * Copyright (C) 2013 Brian Schott
+ * Copyright (C) 2014 Brian Schott
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -151,19 +151,42 @@ int main(string[] args)
 			Log.info("Shutting down.");
 			break serverLoop;
 		case RequestKind.autocomplete:
-			AutocompleteResponse response = complete(request);
-			ubyte[] responseBytes = msgpack.pack(response);
-			s.send(responseBytes);
+			try
+			{
+				AutocompleteResponse response = complete(request);
+				ubyte[] responseBytes = msgpack.pack(response);
+				s.send(responseBytes);
+			}
+			catch (Exception e)
+			{
+				Log.error("Could not handle autocomplete request due to an exception:",
+					e.msg);
+			}
 			break;
 		case RequestKind.doc:
-			AutocompleteResponse response = getDoc(request);
-			ubyte[] responseBytes = msgpack.pack(response);
-			s.send(responseBytes);
+			try
+			{
+				AutocompleteResponse response = getDoc(request);
+				ubyte[] responseBytes = msgpack.pack(response);
+				s.send(responseBytes);
+			}
+			catch (Exception e)
+			{
+				Log.error("Could not get DDoc information", e.msg);
+			}
+
 			break;
 		case RequestKind.symbolLocation:
-			AutocompleteResponse response = findDeclaration(request);
-			ubyte[] responseBytes = msgpack.pack(response);
-			s.send(responseBytes);
+			try
+			{
+				AutocompleteResponse response = findDeclaration(request);
+				ubyte[] responseBytes = msgpack.pack(response);
+				s.send(responseBytes);
+			}
+			catch (Exception e)
+			{
+				Log.error("Could not get symbol location", e.msg);
+			}
 			break;
 		}
 		Log.info("Request processed in ", requestWatch.peek().to!("msecs", float), " milliseconds");
@@ -171,6 +194,9 @@ int main(string[] args)
 	return 0;
 }
 
+/**
+ * Locates the configuration file
+ */
 string getConfigurationLocation()
 {
 	version (useXDG)
@@ -208,6 +234,9 @@ void warnAboutOldConfigLocation()
 	}
 }
 
+/**
+ * Loads import directories from the configuration file
+ */
 string[] loadConfiguredImportDirs()
 {
 	warnAboutOldConfigLocation();
diff --git a/stupidlog.d b/stupidlog.d
index 091b488..49de3f6 100644
--- a/stupidlog.d
+++ b/stupidlog.d
@@ -1,9 +1,7 @@
-/*******************************************************************************
- * Authors: Brian Schott
- * Copyright: Brian Schott
- * Date: Oct  5 2013
+/**
+ * This file is part of DCD, a development tool for the D programming language.
+ * Copyright (C) 2014 Brian Schott
  *
- * License:
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
@@ -16,7 +14,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- ******************************************************************************/
+ */
 
 module stupidlog;