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 dcd.server.autocomplete.symbols;
20 
21 import std.experimental.logger;
22 import std.typecons;
23 
24 import dcd.server.autocomplete.util;
25 
26 import dparse.lexer;
27 import dparse.rollback_allocator;
28 
29 import dsymbol.conversion;
30 import dsymbol.modulecache;
31 import dsymbol.string_interning;
32 import dsymbol.symbol;
33 
34 import dcd.common.messages;
35 
36 import containers.hashset;
37 
38 /**
39  * Finds the declaration of the symbol at the cursor position.
40  * Params:
41  *     request = the autocompletion request
42  * Returns:
43  *     the autocompletion response
44  */
45 public AutocompleteResponse findDeclaration(const AutocompleteRequest request,
46 	ref ModuleCache moduleCache)
47 {
48 	AutocompleteResponse response;
49 	RollbackAllocator rba;
50 	auto allocator = scoped!(ASTAllocator)();
51 	auto cache = StringCache(StringCache.defaultBucketCount);
52 	SymbolStuff stuff = getSymbolsForCompletion(request,
53 		CompletionType.location, allocator, &rba, cache, moduleCache);
54 	scope(exit) stuff.destroy();
55 	if (stuff.symbols.length > 0)
56 	{
57 		response.symbolLocation = stuff.symbols[0].location;
58 		response.symbolFilePath = stuff.symbols[0].symbolFile.idup;
59 	}
60 	else
61 		warning("Could not find symbol declaration");
62 	return response;
63 }
64 
65 /**
66  *
67  */
68 public AutocompleteResponse symbolSearch(const AutocompleteRequest request,
69 	ref ModuleCache moduleCache)
70 {
71 	import containers.ttree : TTree;
72 
73 	LexerConfig config;
74 	config.fileName = "";
75 	auto cache = StringCache(StringCache.defaultBucketCount);
76 	const(Token)[] tokenArray = getTokensForParser(cast(ubyte[]) request.sourceCode,
77 		config, &cache);
78 	auto allocator = scoped!(ASTAllocator)();
79 	RollbackAllocator rba;
80 	ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray, allocator,
81 		&rba, request.cursorPosition, moduleCache);
82 	scope(exit) pair.destroy();
83 
84 	static struct SearchResults
85 	{
86 		void put(const(DSymbol)* symbol)
87 		{
88 			tree.insert(SearchResult(symbol));
89 		}
90 
91 		static struct SearchResult
92 		{
93 			const(DSymbol)* symbol;
94 
95 			int opCmp(ref const SearchResult other) const pure nothrow @nogc @safe
96 			{
97 				if (other.symbol.symbolFile < symbol.symbolFile)
98 					return -1;
99 				if (other.symbol.symbolFile > symbol.symbolFile)
100 					return 1;
101 				if (other.symbol.location < symbol.location)
102 					return -1;
103 				return other.symbol.location > symbol.location;
104 			}
105 		}
106 
107 		TTree!(SearchResult) tree;
108 	}
109 
110 	SearchResults results;
111 	HashSet!size_t visited;
112 	foreach (symbol; pair.scope_.symbols)
113 		symbol.getParts!SearchResults(internString(request.searchName), results, visited);
114 	foreach (s; moduleCache.getAllSymbols())
115 		s.symbol.getParts!SearchResults(internString(request.searchName), results, visited);
116 
117 	AutocompleteResponse response;
118 	foreach (result; results.tree[])
119 		response.completions ~= makeSymbolCompletionInfo(result.symbol, result.symbol.kind);
120 
121 	return response;
122 }