diff --git a/src/server/autocomplete/complete.d b/src/server/autocomplete/complete.d
index 83f7a91..8e7b079 100644
--- a/src/server/autocomplete/complete.d
+++ b/src/server/autocomplete/complete.d
@@ -59,12 +59,8 @@ public AutocompleteResponse complete(const AutocompleteRequest request,
 		request.cursorPosition, stringCache, tokenArray);
 	if (beforeTokens.length >= 2)
 	{
-		if (beforeTokens[$ - 1] == tok!"(" || beforeTokens[$ - 1] == tok!"[")
-		{
-			return parenCompletion(beforeTokens, tokenArray, request.cursorPosition,
-				moduleCache);
-		}
-		else if (beforeTokens[$ - 1] == tok!",")
+		if (beforeTokens[$ - 1] == tok!"(" || beforeTokens[$ - 1] == tok!"["
+			|| beforeTokens[$ - 1] == tok!",")
 		{
 			immutable size_t end = goBackToOpenParen(beforeTokens);
 			if (end != size_t.max)
@@ -80,7 +76,7 @@ public AutocompleteResponse complete(const AutocompleteRequest request,
 					beforeTokens = beforeTokens[$-1 .. $];
 				return dotCompletion(beforeTokens, tokenArray, request.cursorPosition,
 					moduleCache);
-            }
+			}
 			else
 				return importCompletion(beforeTokens, kind, moduleCache);
 		}
@@ -122,16 +118,14 @@ AutocompleteResponse dotCompletion(T)(T beforeTokens, const(Token)[] tokenArray,
 		significantTokenType = tok!"identifier";
 		beforeTokens = beforeTokens[0 .. $ - 1];
 	}
-	else if (beforeTokens.length >= 2 && beforeTokens[$ - 1] ==  tok!".")
+	else if (beforeTokens.length >= 2 && beforeTokens[$ - 1] == tok!".")
 		significantTokenType = beforeTokens[$ - 2].type;
 	else
 		return response;
 
 	switch (significantTokenType)
 	{
-	case tok!"stringLiteral":
-	case tok!"wstringLiteral":
-	case tok!"dstringLiteral":
+	mixin(STRING_LITERAL_CASES);
 		foreach (symbol; arraySymbols)
 		{
 			response.completionKinds ~= symbol.kind;
@@ -139,34 +133,9 @@ AutocompleteResponse dotCompletion(T)(T beforeTokens, const(Token)[] tokenArray,
 		}
 		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":
+	mixin(TYPE_IDENT_CASES);
 	case tok!")":
 	case tok!"]":
-	case tok!"this":
-	case tok!"super":
 		auto allocator = scoped!(ASTAllocator)();
 		RollbackAllocator rba;
 		ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray, allocator,
@@ -227,7 +196,6 @@ AutocompleteResponse parenCompletion(T)(T beforeTokens,
 		break;
 	case tok!"characterLiteral":
 	case tok!"doubleLiteral":
-	case tok!"dstringLiteral":
 	case tok!"floatLiteral":
 	case tok!"identifier":
 	case tok!"idoubleLiteral":
@@ -236,14 +204,13 @@ AutocompleteResponse parenCompletion(T)(T beforeTokens,
 	case tok!"irealLiteral":
 	case tok!"longLiteral":
 	case tok!"realLiteral":
-	case tok!"stringLiteral":
 	case tok!"uintLiteral":
 	case tok!"ulongLiteral":
-	case tok!"wstringLiteral":
 	case tok!"this":
 	case tok!"super":
 	case tok!")":
 	case tok!"]":
+	mixin(STRING_LITERAL_CASES);
 		auto allocator = scoped!(ASTAllocator)();
 		RollbackAllocator rba;
 		ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray, allocator,
diff --git a/src/server/autocomplete/util.d b/src/server/autocomplete/util.d
index d2da8c9..f9f1263 100644
--- a/src/server/autocomplete/util.d
+++ b/src/server/autocomplete/util.d
@@ -147,36 +147,15 @@ SymbolStuff getSymbolsForCompletion(const AutocompleteRequest request,
 		request.cursorPosition, type), pair.symbol, pair.scope_);
 }
 
-static void skip(alias O, alias C, T)(T t, ref size_t i)
-{
-	int depth = 1;
-	while (i < t.length) switch (t[i].type)
-	{
-	case O:
-		i++;
-		depth++;
-		break;
-	case C:
-		i++;
-		depth--;
-		if (depth <= 0)
-			return;
-		break;
-	default:
-		i++;
-		break;
-	}
-}
-
 bool isSliceExpression(T)(T tokens, size_t index)
 {
 	while (index < tokens.length) switch (tokens[index].type)
 	{
 	case tok!"[":
-		skip!(tok!"[", tok!"]")(tokens, index);
+		tokens.skipParen(index, tok!"[", tok!"]");
 		break;
 	case tok!"(":
-		skip!(tok!"(", tok!")")(tokens, index);
+		tokens.skipParen(index, tok!"(", tok!")");
 		break;
 	case tok!"]":
 	case tok!"}":
@@ -200,22 +179,6 @@ DSymbol*[] getSymbolsByTokenChain(T)(Scope* completionScope,
 	//dumpTokens(tokens.release);
 	//writeln(">>>");
 
-	static size_t skipEnd(T tokenSlice, size_t i, IdType open, IdType close)
-	{
-		size_t j = i + 1;
-		for (int depth = 1; depth > 0 && j < tokenSlice.length; j++)
-		{
-			if (tokenSlice[j].type == open)
-				depth++;
-			else if (tokenSlice[j].type == close)
-			{
-				depth--;
-				if (depth == 0) break;
-			}
-		}
-		return j;
-	}
-
 	// Find the symbol corresponding to the beginning of the chain
 	DSymbol*[] symbols;
 	if (tokens.length == 0)
@@ -224,7 +187,8 @@ DSymbol*[] getSymbolsByTokenChain(T)(Scope* completionScope,
 	// e.g. (a.b!c).d
 	if (tokens[0] == tok!"(")
 	{
-		immutable j = skipEnd(tokens, 0, tok!"(", tok!")");
+		size_t j;
+		tokens.skipParen(j, tok!"(", tok!")");
 		symbols = getSymbolsByTokenChain(completionScope, tokens[1 .. j],
 				cursorPosition, completionType);
 		tokens = tokens[j + 1 .. $];
@@ -307,7 +271,7 @@ DSymbol*[] getSymbolsByTokenChain(T)(Scope* completionScope,
 	{
 		void skip(IdType open, IdType close)
 		{
-			i = skipEnd(tokens, i, open, close);
+			tokens.skipParen(i, open, close);
 		}
 
 		switch (tokens[i].type)
@@ -438,7 +402,7 @@ DSymbol*[] getSymbolsByTokenChain(T)(Scope* completionScope,
 	return symbols;
 }
 
-private enum TYPE_IDENT_AND_LITERAL_CASES = q{
+enum TYPE_IDENT_CASES = q{
 	case tok!"int":
 	case tok!"uint":
 	case tok!"long":
@@ -465,11 +429,16 @@ private enum TYPE_IDENT_AND_LITERAL_CASES = q{
 	case tok!"this":
 	case tok!"super":
 	case tok!"identifier":
+};
+
+enum STRING_LITERAL_CASES = q{
 	case tok!"stringLiteral":
 	case tok!"wstringLiteral":
 	case tok!"dstringLiteral":
 };
 
+enum TYPE_IDENT_AND_LITERAL_CASES = TYPE_IDENT_CASES ~ STRING_LITERAL_CASES;
+
 /**
  *
  */
@@ -516,18 +485,7 @@ T getExpression(T)(T beforeTokens)
 		skip:
 			mixin (EXPRESSION_LOOP_BREAK);
 			immutable bookmark = i;
-			int depth = 1;
-			do
-			{
-				if (depth == 0 || i == 0)
-					break;
-				else
-					i--;
-				if (beforeTokens[i].type == open)
-					depth++;
-				else if (beforeTokens[i].type == close)
-					depth--;
-			} while (true);
+			i = beforeTokens.skipParenReverse(i, open, close);
 
 			skipCount++;
 
@@ -622,11 +580,11 @@ bool isUdaExpression(T)(ref T tokens)
 {
 	bool result;
 	ptrdiff_t skip;
-	ptrdiff_t i = tokens.length - 2;
-	
+	auto i = cast(ptrdiff_t) tokens.length - 2;
+
 	if (i < 1)
 		return result;
-	
+
 	// skips the UDA ctor
 	if (tokens[i].type == tok!")")
 	{
@@ -650,7 +608,7 @@ bool isUdaExpression(T)(ref T tokens)
 			}
 		}
 	}
-	
+
 	if (skip == 0)
 	{
 		// @UDA!SingleTemplateParameter
@@ -665,10 +623,14 @@ bool isUdaExpression(T)(ref T tokens)
 			result = true;
 		}
 	}
-    
+
 	return result;
 }
 
+/**
+ * Traverses a token slice in reverse to find the opening parentheses or square bracket
+ * that begins the block the last token is in.
+ */
 size_t goBackToOpenParen(T)(T beforeTokens)
 in
 {
@@ -677,8 +639,6 @@ in
 body
 {
 	size_t i = beforeTokens.length - 1;
-	IdType open;
-	IdType close;
 	while (true) switch (beforeTokens[i].type)
 	{
 	case tok!",":
@@ -706,36 +666,75 @@ body
 	case tok!"[":
 		return i + 1;
 	case tok!")":
-		open = tok!")";
-		close = tok!"(";
-		goto skip;
+		i = beforeTokens.skipParenReverseBefore(i, tok!")", tok!"(");
+		break;
 	case tok!"}":
-		open = tok!"}";
-		close = tok!"{";
-		goto skip;
+		i = beforeTokens.skipParenReverseBefore(i, tok!"}", tok!"{");
+		break;
 	case tok!"]":
-		open = tok!"]";
-		close = tok!"[";
-	skip:
-		if (i == 0)
-			return size_t.max;
-		else
-			i--;
-		int depth = 1;
-		do
-		{
-			if (depth == 0 || i == 0)
-				break;
-			else
-				i--;
-			if (beforeTokens[i].type == open)
-				depth++;
-			else if (beforeTokens[i].type == close)
-				depth--;
-		} while (true);
+		i = beforeTokens.skipParenReverseBefore(i, tok!"]", tok!"[");
 		break;
 	default:
 		return size_t.max;
 	}
-	return size_t.max;
+}
+
+/**
+ * Skips blocks of parentheses until the starting block has been closed
+ */
+void skipParen(T)(T tokenSlice, ref size_t i, IdType open, IdType close)
+{
+	if (i >= tokenSlice.length || tokenSlice.length <= 0)
+		return;
+	int depth = 1;
+	while (depth != 0 && i + 1 != tokenSlice.length)
+	{
+		i++;
+		if (tokenSlice[i].type == open)
+			depth++;
+		else if (tokenSlice[i].type == close)
+			depth--;
+	}
+}
+
+/**
+ * Skips blocks of parentheses in reverse until the starting block has been opened
+ */
+size_t skipParenReverse(T)(T beforeTokens, size_t i, IdType open, IdType close)
+{
+	if (i == 0)
+		return 0;
+	int depth = 1;
+	while (depth != 0 && i != 0)
+	{
+		i--;
+		if (beforeTokens[i].type == open)
+			depth++;
+		else if (beforeTokens[i].type == close)
+			depth--;
+	}
+	return i;
+}
+
+size_t skipParenReverseBefore(T)(T beforeTokens, size_t i, IdType open, IdType close)
+{
+	i = skipParenReverse(beforeTokens, i, open, close);
+	if (i != 0)
+		i--;
+	return i;
+}
+
+///
+unittest
+{
+	Token[] t = [
+		Token(tok!"identifier"), Token(tok!"identifier"), Token(tok!"("),
+		Token(tok!"identifier"), Token(tok!"("), Token(tok!")"), Token(tok!",")
+	];
+	size_t i = t.length - 1;
+	i = skipParenReverse(t, i, tok!")", tok!"(");
+	assert(i == 2);
+	i = t.length - 1;
+	i = skipParenReverseBefore(t, i, tok!")", tok!"(");
+	assert(i == 1);
 }
diff --git a/tests/tc058/expected1.txt b/tests/tc058/expected1.txt
new file mode 100644
index 0000000..8bc98d2
--- /dev/null
+++ b/tests/tc058/expected1.txt
@@ -0,0 +1,2 @@
+calltips
+void doStuff(int a, int b)
diff --git a/tests/tc058/file.d b/tests/tc058/file.d
new file mode 100644
index 0000000..80072ce
--- /dev/null
+++ b/tests/tc058/file.d
@@ -0,0 +1,8 @@
+void doStuff(int a, int b) { return; }
+int getInt(int i, int[] b) { return i; }
+int b(int a) { return a; }
+void main(string[] args)
+{
+	doStuff(getInt(1, [b(3)]),);
+	auto x = 10, 20;
+}
diff --git a/tests/tc058/run.sh b/tests/tc058/run.sh
new file mode 100755
index 0000000..3376eea
--- /dev/null
+++ b/tests/tc058/run.sh
@@ -0,0 +1,5 @@
+set -e
+set -u
+
+../../bin/dcd-client $1 file.d -c161 > actual1.txt
+diff actual1.txt expected1.txt