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