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 moduledsymbol.scope_;
20 21 importdsymbol.symbol;
22 importdsymbol.import_;
23 importdsymbol.builtin.names;
24 importcontainers.ttree;
25 importcontainers.unrolledlist;
26 importstd.experimental.logger;
27 importstdx.allocator.mallocator : Mallocator;
28 29 /**
30 * Contains symbols and supports lookup of symbols by cursor position.
31 */32 structScope33 {
34 @disablethis(this);
35 @disablethis();
36 37 /**
38 * Params:
39 * begin = the beginning byte index
40 * end = the ending byte index
41 */42 this (uintbegin, uintend)
43 {
44 this.startLocation = begin;
45 this.endLocation = end;
46 }
47 48 ~this()
49 {
50 foreach (child; children[])
51 typeid(Scope).destroy(child);
52 foreach (symbol; _symbols)
53 {
54 if (symbol.owned)
55 typeid(DSymbol).destroy(symbol.ptr);
56 }
57 }
58 59 /**
60 * Params:
61 * cursorPosition = the cursor position in bytes
62 * Returns:
63 * the innermost scope that contains the given cursor position
64 */65 Scope* getScopeByCursor(size_tcursorPosition) pure @nogc66 {
67 if (cursorPosition < startLocation) returnnull;
68 if (cursorPosition > endLocation) returnnull;
69 foreach (child; children[])
70 {
71 autochildScope = child.getScopeByCursor(cursorPosition);
72 if (childScope !isnull)
73 returnchildScope;
74 }
75 returncast(typeof(return)) &this;
76 }
77 78 /**
79 * Params:
80 * cursorPosition = the cursor position in bytes
81 * Returns:
82 * all symbols in the scope containing the cursor position, as well as
83 * the symbols in parent scopes of that scope.
84 */85 DSymbol*[] getSymbolsInCursorScope(size_tcursorPosition)
86 {
87 importstd.array : array;
88 importstd.algorithm.iteration : map;
89 90 autos = getScopeByCursor(cursorPosition);
91 92 if (sisnull)
93 return [];
94 95 UnrolledList!(DSymbol*) retVal;
96 Scope* sc = s;
97 while (sc !isnull)
98 {
99 foreach (item; sc._symbols[])
100 {
101 if (item.ptr.kind == CompletionKind.withSymbol)
102 {
103 if (item.ptr.type !isnull)
104 foreach (i; item.ptr.type.opSlice())
105 retVal.insert(i);
106 }
107 elseif (item.ptr.type !isnull && item.ptr.kind == CompletionKind.importSymbol)
108 {
109 if (item.ptr.qualifier != SymbolQualifier.selectiveImport)
110 {
111 foreach (i; item.ptr.type.opSlice())
112 retVal.insert(i);
113 }
114 elseif (item.ptr !isnull)
115 retVal.insert(item.ptr.type);
116 }
117 else118 retVal.insert(item.ptr);
119 }
120 sc = sc.parent;
121 }
122 returnarray(retVal[]);
123 }
124 125 /**
126 * Params:
127 * name = the symbol name to search for
128 * Returns:
129 * all symbols in this scope or parent scopes with the given name
130 */131 inout(DSymbol)*[] getSymbolsByName(istringname) inout132 {
133 importstd.array : array, appender;
134 importstd.algorithm.iteration : map;
135 136 DSymbols = DSymbol(name);
137 autoer = _symbols.equalRange(SymbolOwnership(&s));
138 if (!er.empty)
139 returncast(typeof(return)) array(er.map!(a => a.ptr));
140 141 // Check symbols from "with" statement142 DSymbolir2 = DSymbol(WITH_SYMBOL_NAME);
143 autor2 = _symbols.equalRange(SymbolOwnership(&ir2));
144 if (!r2.empty)
145 {
146 autoapp = appender!(DSymbol*[])();
147 foreach (e; r2)
148 {
149 if (e.typeisnull)
150 continue;
151 foreach (withSymbol; e.type.getPartsByName(s.name))
152 app.put(cast(DSymbol*) withSymbol);
153 }
154 if (app.data.length > 0)
155 returncast(typeof(return)) app.data;
156 }
157 158 if (name.ptr != CONSTRUCTOR_SYMBOL_NAME.ptr159 && name.ptr != DESTRUCTOR_SYMBOL_NAME.ptr160 && name.ptr != UNITTEST_SYMBOL_NAME.ptr161 && name.ptr != THIS_SYMBOL_NAME.ptr)
162 {
163 // Check imported symbols164 DSymbolir = DSymbol(IMPORT_SYMBOL_NAME);
165 166 autoapp = appender!(DSymbol*[])();
167 foreach (e; _symbols.equalRange(SymbolOwnership(&ir)))
168 {
169 if (e.typeisnull)
170 continue;
171 if (e.qualifier == SymbolQualifier.selectiveImport &&
172 e.type.name.ptr == name.ptr)
173 app.put(cast(DSymbol*) e.type);
174 else175 foreach (importedSymbol; e.type.getPartsByName(s.name))
176 app.put(cast(DSymbol*) importedSymbol);
177 }
178 if (app.data.length > 0)
179 returncast(typeof(return)) app.data;
180 }
181 if (parentisnull)
182 return [];
183 returnparent.getSymbolsByName(name);
184 }
185 186 /**
187 * Params:
188 * name = the symbol name to search for
189 * cursorPosition = the cursor position in bytes
190 * Returns:
191 * all symbols with the given name in the scope containing the cursor
192 * and its parent scopes
193 */194 DSymbol*[] getSymbolsByNameAndCursor(istringname, size_tcursorPosition)
195 {
196 autos = getScopeByCursor(cursorPosition);
197 if (sisnull)
198 return [];
199 returns.getSymbolsByName(name);
200 }
201 202 DSymbol* getFirstSymbolByNameAndCursor(istringname, size_tcursorPosition)
203 {
204 autos = getSymbolsByNameAndCursor(name, cursorPosition);
205 returns.length > 0 ? s[0] : null;
206 }
207 208 /**
209 * Returns an array of symbols that are present at global scope
210 */211 inout(DSymbol)*[] getSymbolsAtGlobalScope(istringname) inout212 {
213 if (parent !isnull)
214 returnparent.getSymbolsAtGlobalScope(name);
215 returngetSymbolsByName(name);
216 }
217 218 /// The scope that contains this one219 Scope* parent;
220 221 /// Child scopes222 UnrolledList!(Scope*, Mallocator, false) children;
223 224 /// Start location of this scope in bytes225 uintstartLocation;
226 227 /// End location of this scope in bytes228 uintendLocation;
229 230 autosymbols() @property231 {
232 return_symbols[];
233 }
234 235 /**
236 * Adds the given symbol to this scope.
237 * Params:
238 * symbol = the symbol to add
239 * owns = if true, the symbol's destructor will be called when this
240 * scope's destructor is called.
241 */242 voidaddSymbol(DSymbol* symbol, boolowns)
243 {
244 assert(symbol !isnull);
245 _symbols.insert(SymbolOwnership(symbol, owns));
246 }
247 248 private:
249 /// Symbols contained in this scope250 TTree!(SymbolOwnership, Mallocator, true, "a.opCmp(b) < 0", false) _symbols;
251 }