1 // Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 // THE SOFTWARE.
20
21 #include "Symbol.h"
22 #include "Symbols.h"
23 #include "Control.h"
24 #include "Names.h"
25 #include "TranslationUnit.h"
26 #include "Literals.h"
27 #include "MemoryPool.h"
28 #include "SymbolVisitor.h"
29 #include "NameVisitor.h"
30 #include "Scope.h"
31 #include "Templates.h"
32
33 #include "cppassert.h"
34
35 #include <utils/link.h>
36
37 using namespace CPlusPlus;
38
39 class Symbol::HashCode: protected NameVisitor
40 {
41 public:
HashCode()42 HashCode()
43 : _value(0)
44 { }
45
~HashCode()46 virtual ~HashCode()
47 { }
48
operator ()(const Name * name)49 unsigned operator()(const Name *name)
50 {
51 unsigned previousValue = switchValue(0);
52 accept(name);
53 return switchValue(previousValue);
54 }
55
56 protected:
switchValue(unsigned value)57 unsigned switchValue(unsigned value)
58 {
59 unsigned previousValue = _value;
60 _value = value;
61 return previousValue;
62 }
63
visit(const Identifier * name)64 virtual void visit(const Identifier *name)
65 { _value = name->identifier()->hashCode(); }
66
visit(const TemplateNameId * name)67 virtual void visit(const TemplateNameId *name)
68 { _value = name->identifier()->hashCode(); }
69
visit(const DestructorNameId * name)70 virtual void visit(const DestructorNameId *name)
71 { _value = name->identifier()->hashCode(); }
72
visit(const OperatorNameId * name)73 virtual void visit(const OperatorNameId *name)
74 { _value = unsigned(name->kind()); }
75
visit(const ConversionNameId *)76 virtual void visit(const ConversionNameId *)
77 { _value = 0; } // ### TODO: implement me
78
visit(const QualifiedNameId * name)79 virtual void visit(const QualifiedNameId *name)
80 { _value = operator()(name->name()); }
81
visit(const SelectorNameId * name)82 virtual void visit(const SelectorNameId *name)
83 { _value = name->identifier()->hashCode(); }
84
85 private:
86 unsigned _value;
87 };
88
Symbol(TranslationUnit * translationUnit,int sourceLocation,const Name * name)89 Symbol::Symbol(TranslationUnit *translationUnit, int sourceLocation, const Name *name)
90 : _name(nullptr),
91 _enclosingScope(nullptr),
92 _next(nullptr),
93 _fileId(nullptr),
94 _sourceLocation(0),
95 _hashCode(0),
96 _storage(Symbol::NoStorage),
97 _visibility(Symbol::Public),
98 _index(0),
99 _line(0),
100 _column(0),
101 _isGenerated(false),
102 _isDeprecated(false),
103 _isUnavailable(false)
104 {
105 setSourceLocation(sourceLocation, translationUnit);
106 setName(name);
107 }
108
Symbol(Clone * clone,Subst * subst,Symbol * original)109 Symbol::Symbol(Clone *clone, Subst *subst, Symbol *original)
110 : _name(clone->name(original->_name, subst)),
111 _enclosingScope(nullptr),
112 _next(nullptr),
113 _fileId(clone->control()->stringLiteral(original->fileName(), original->fileNameLength())),
114 _sourceLocation(original->_sourceLocation),
115 _hashCode(original->_hashCode),
116 _storage(original->_storage),
117 _visibility(original->_visibility),
118 _index(0),
119 _line(original->_line),
120 _column(original->_column),
121 _isGenerated(original->_isGenerated),
122 _isDeprecated(original->_isDeprecated),
123 _isUnavailable(original->_isUnavailable)
124 {
125 }
126
~Symbol()127 Symbol::~Symbol()
128 { }
129
visitSymbol(SymbolVisitor * visitor)130 void Symbol::visitSymbol(SymbolVisitor *visitor)
131 {
132 if (visitor->preVisit(this))
133 visitSymbol0(visitor);
134 visitor->postVisit(this);
135 }
136
visitSymbol(Symbol * symbol,SymbolVisitor * visitor)137 void Symbol::visitSymbol(Symbol *symbol, SymbolVisitor *visitor)
138 {
139 if (! symbol)
140 return;
141
142 symbol->visitSymbol(visitor);
143 }
144
sourceLocation() const145 int Symbol::sourceLocation() const
146 { return _sourceLocation; }
147
isGenerated() const148 bool Symbol::isGenerated() const
149 { return _isGenerated; }
150
isDeprecated() const151 bool Symbol::isDeprecated() const
152 { return _isDeprecated; }
153
setDeprecated(bool isDeprecated)154 void Symbol::setDeprecated(bool isDeprecated)
155 { _isDeprecated = isDeprecated; }
156
isUnavailable() const157 bool Symbol::isUnavailable() const
158 { return _isUnavailable; }
159
setUnavailable(bool isUnavailable)160 void Symbol::setUnavailable(bool isUnavailable)
161 { _isUnavailable = isUnavailable; }
162
setSourceLocation(int sourceLocation,TranslationUnit * translationUnit)163 void Symbol::setSourceLocation(int sourceLocation, TranslationUnit *translationUnit)
164 {
165 _sourceLocation = sourceLocation;
166
167 if (translationUnit) {
168 const Token &tk = translationUnit->tokenAt(sourceLocation);
169 _isGenerated = tk.generated();
170 translationUnit->getPosition(tk.utf16charsBegin(), &_line, &_column, &_fileId);
171 } else {
172 _isGenerated = false;
173 _line = 0;
174 _column = 0;
175 _fileId = nullptr;
176 }
177 }
178
line() const179 int Symbol::line() const
180 {
181 return _line;
182 }
183
column() const184 int Symbol::column() const
185 {
186 return _column;
187 }
188
fileId() const189 const StringLiteral *Symbol::fileId() const
190 {
191 return _fileId;
192 }
193
fileName() const194 const char *Symbol::fileName() const
195 { return _fileId ? _fileId->chars() : ""; }
196
fileNameLength() const197 int Symbol::fileNameLength() const
198 { return _fileId ? _fileId->size() : 0; }
199
unqualifiedName() const200 const Name *Symbol::unqualifiedName() const
201 {
202 if (! _name)
203 return nullptr;
204
205 else if (const QualifiedNameId *q = _name->asQualifiedNameId())
206 return q->name();
207
208 return _name;
209 }
210
name() const211 const Name *Symbol::name() const
212 { return _name; }
213
setName(const Name * name)214 void Symbol::setName(const Name *name)
215 {
216 _name = name;
217
218 if (! _name)
219 _hashCode = 0;
220 else {
221 HashCode hh;
222 _hashCode = hh(unqualifiedName());
223 }
224 }
225
identifier() const226 const Identifier *Symbol::identifier() const
227 {
228 if (_name)
229 return _name->identifier();
230
231 return nullptr;
232 }
233
enclosingScope() const234 Scope *Symbol::enclosingScope() const
235 { return _enclosingScope; }
236
setEnclosingScope(Scope * scope)237 void Symbol::setEnclosingScope(Scope *scope)
238 {
239 CPP_CHECK(! _enclosingScope);
240 _enclosingScope = scope;
241 }
242
resetEnclosingScope()243 void Symbol::resetEnclosingScope()
244 {
245 _enclosingScope = nullptr;
246 }
247
enclosingNamespace() const248 Namespace *Symbol::enclosingNamespace() const
249 {
250 for (Scope *s = _enclosingScope; s; s = s->enclosingScope()) {
251 if (Namespace *ns = s->asNamespace())
252 return ns;
253 }
254 return nullptr;
255 }
256
enclosingTemplate() const257 Template *Symbol::enclosingTemplate() const
258 {
259 for (Scope *s = _enclosingScope; s; s = s->enclosingScope()) {
260 if (Template *templ = s->asTemplate())
261 return templ;
262 }
263 return nullptr;
264 }
265
enclosingClass() const266 Class *Symbol::enclosingClass() const
267 {
268 for (Scope *s = _enclosingScope; s; s = s->enclosingScope()) {
269 if (Class *klass = s->asClass())
270 return klass;
271 }
272 return nullptr;
273 }
274
enclosingEnum() const275 Enum *Symbol::enclosingEnum() const
276 {
277 for (Scope *s = _enclosingScope; s; s = s->enclosingScope()) {
278 if (Enum *e = s->asEnum())
279 return e;
280 }
281 return nullptr;
282 }
283
enclosingFunction() const284 Function *Symbol::enclosingFunction() const
285 {
286 for (Scope *s = _enclosingScope; s; s = s->enclosingScope()) {
287 if (Function *fun = s->asFunction())
288 return fun;
289 }
290 return nullptr;
291 }
292
enclosingBlock() const293 Block *Symbol::enclosingBlock() const
294 {
295 for (Scope *s = _enclosingScope; s; s = s->enclosingScope()) {
296 if (Block *block = s->asBlock())
297 return block;
298 }
299 return nullptr;
300 }
301
index() const302 unsigned Symbol::index() const
303 { return _index; }
304
next() const305 Symbol *Symbol::next() const
306 { return _next; }
307
hashCode() const308 unsigned Symbol::hashCode() const
309 { return _hashCode; }
310
storage() const311 int Symbol::storage() const
312 { return _storage; }
313
setStorage(int storage)314 void Symbol::setStorage(int storage)
315 { _storage = storage; }
316
visibility() const317 int Symbol::visibility() const
318 { return _visibility; }
319
setVisibility(int visibility)320 void Symbol::setVisibility(int visibility)
321 { _visibility = visibility; }
322
isFriend() const323 bool Symbol::isFriend() const
324 { return _storage == Friend; }
325
isRegister() const326 bool Symbol::isRegister() const
327 { return _storage == Register; }
328
isStatic() const329 bool Symbol::isStatic() const
330 { return _storage == Static; }
331
isExtern() const332 bool Symbol::isExtern() const
333 { return _storage == Extern; }
334
isMutable() const335 bool Symbol::isMutable() const
336 { return _storage == Mutable; }
337
isTypedef() const338 bool Symbol::isTypedef() const
339 { return _storage == Typedef; }
340
isPublic() const341 bool Symbol::isPublic() const
342 { return _visibility == Public; }
343
isProtected() const344 bool Symbol::isProtected() const
345 { return _visibility == Protected; }
346
isPrivate() const347 bool Symbol::isPrivate() const
348 { return _visibility == Private; }
349
isScope() const350 bool Symbol::isScope() const
351 { return asScope() != nullptr; }
352
isEnum() const353 bool Symbol::isEnum() const
354 { return asEnum() != nullptr; }
355
isFunction() const356 bool Symbol::isFunction() const
357 { return asFunction() != nullptr; }
358
isNamespace() const359 bool Symbol::isNamespace() const
360 { return asNamespace() != nullptr; }
361
isTemplate() const362 bool Symbol::isTemplate() const
363 { return asTemplate() != nullptr; }
364
isClass() const365 bool Symbol::isClass() const
366 { return asClass() != nullptr; }
367
isForwardClassDeclaration() const368 bool Symbol::isForwardClassDeclaration() const
369 { return asForwardClassDeclaration() != nullptr; }
370
isQtPropertyDeclaration() const371 bool Symbol::isQtPropertyDeclaration() const
372 { return asQtPropertyDeclaration() != nullptr; }
373
isQtEnum() const374 bool Symbol::isQtEnum() const
375 { return asQtEnum() != nullptr; }
376
isBlock() const377 bool Symbol::isBlock() const
378 { return asBlock() != nullptr; }
379
isUsingNamespaceDirective() const380 bool Symbol::isUsingNamespaceDirective() const
381 { return asUsingNamespaceDirective() != nullptr; }
382
isUsingDeclaration() const383 bool Symbol::isUsingDeclaration() const
384 { return asUsingDeclaration() != nullptr; }
385
isDeclaration() const386 bool Symbol::isDeclaration() const
387 { return asDeclaration() != nullptr; }
388
isArgument() const389 bool Symbol::isArgument() const
390 { return asArgument() != nullptr; }
391
isTypenameArgument() const392 bool Symbol::isTypenameArgument() const
393 { return asTypenameArgument() != nullptr; }
394
isBaseClass() const395 bool Symbol::isBaseClass() const
396 { return asBaseClass() != nullptr; }
397
isObjCBaseClass() const398 bool Symbol::isObjCBaseClass() const
399 { return asObjCBaseClass() != nullptr; }
400
isObjCBaseProtocol() const401 bool Symbol::isObjCBaseProtocol() const
402 { return asObjCBaseProtocol() != nullptr; }
403
isObjCClass() const404 bool Symbol::isObjCClass() const
405 { return asObjCClass() != nullptr; }
406
isObjCForwardClassDeclaration() const407 bool Symbol::isObjCForwardClassDeclaration() const
408 { return asObjCForwardClassDeclaration() != nullptr; }
409
isObjCProtocol() const410 bool Symbol::isObjCProtocol() const
411 { return asObjCProtocol() != nullptr; }
412
isObjCForwardProtocolDeclaration() const413 bool Symbol::isObjCForwardProtocolDeclaration() const
414 { return asObjCForwardProtocolDeclaration() != nullptr; }
415
isObjCMethod() const416 bool Symbol::isObjCMethod() const
417 { return asObjCMethod() != nullptr; }
418
isObjCPropertyDeclaration() const419 bool Symbol::isObjCPropertyDeclaration() const
420 { return asObjCPropertyDeclaration() != nullptr; }
421
copy(Symbol * other)422 void Symbol::copy(Symbol *other)
423 {
424 _sourceLocation = other->_sourceLocation;
425 _name = other->_name;
426 _hashCode = other->_hashCode;
427 _storage = other->_storage;
428 _visibility = other->_visibility;
429 _enclosingScope = other->_enclosingScope;
430 _index = other->_index;
431 _next = other->_next;
432 _fileId = other->_fileId;
433 _line = other->_line;
434 _column = other->_column;
435
436 _isGenerated = other->_isGenerated;
437 _isDeprecated = other->_isDeprecated;
438 }
439
toLink() const440 Utils::Link Symbol::toLink() const
441 {
442 const QString filename = QString::fromUtf8(fileName(), fileNameLength());
443
444 int line = this->line();
445 int column = this->column();
446
447 if (column)
448 --column;
449
450 if (isGenerated())
451 column = 0;
452
453 return Utils::Link(Utils::FilePath::fromString(filename), line, column);
454 }
455