OSDN Git Service

It's 2011 now.
[qt-creator-jp/qt-creator-jp.git] / src / libs / cplusplus / CppRewriter.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33 #include "CppRewriter.h"
34 #include <TypeVisitor.h>
35 #include <NameVisitor.h>
36 #include <CoreTypes.h>
37 #include <Symbols.h>
38 #include <Literals.h>
39 #include <Names.h>
40 #include <Scope.h>
41 #include <Overview.h>
42
43 #include <QtCore/QVarLengthArray>
44 #include <QtCore/QRegExp>
45 #include <QtCore/QDebug>
46
47 namespace CPlusPlus {
48
49 class Rewrite
50 {
51 public:
52     Rewrite(Control *control, SubstitutionEnvironment *env)
53         : control(control), env(env), rewriteType(this), rewriteName(this) {}
54
55     class RewriteType: public TypeVisitor
56     {
57         Rewrite *rewrite;
58         QList<FullySpecifiedType> temps;
59
60         Control *control() const
61         { return rewrite->control; }
62
63         void accept(const FullySpecifiedType &ty)
64         {
65             TypeVisitor::accept(ty.type());
66             unsigned flags = ty.flags();
67             flags |= temps.back().flags();
68             temps.back().setFlags(flags);
69         }
70
71     public:
72         RewriteType(Rewrite *r): rewrite(r) {}
73
74         FullySpecifiedType operator()(const FullySpecifiedType &ty)
75         {
76             accept(ty);
77             return temps.takeLast();
78         }
79
80         virtual void visit(UndefinedType *)
81         {
82             temps.append(FullySpecifiedType());
83         }
84
85         virtual void visit(VoidType *)
86         {
87             temps.append(control()->voidType());
88         }
89
90         virtual void visit(IntegerType *type)
91         {
92             temps.append(control()->integerType(type->kind()));
93         }
94
95         virtual void visit(FloatType *type)
96         {
97             temps.append(control()->floatType(type->kind()));
98         }
99
100         virtual void visit(PointerToMemberType *type)
101         {
102             const Name *memberName = rewrite->rewriteName(type->memberName());
103             const FullySpecifiedType elementType = rewrite->rewriteType(type->elementType());
104             temps.append(control()->pointerToMemberType(memberName, elementType));
105         }
106
107         virtual void visit(PointerType *type)
108         {
109             const FullySpecifiedType elementType = rewrite->rewriteType(type->elementType());
110             temps.append(control()->pointerType(elementType));
111         }
112
113         virtual void visit(ReferenceType *type)
114         {
115             const FullySpecifiedType elementType = rewrite->rewriteType(type->elementType());
116             temps.append(control()->referenceType(elementType));
117         }
118
119         virtual void visit(ArrayType *type)
120         {
121             const FullySpecifiedType elementType = rewrite->rewriteType(type->elementType());
122             temps.append(control()->arrayType(elementType, type->size()));
123         }
124
125         virtual void visit(NamedType *type)
126         {
127             FullySpecifiedType ty = rewrite->env->apply(type->name(), rewrite);
128             if (! ty->isUndefinedType())
129                 temps.append(ty);
130             else {
131                 const Name *name = rewrite->rewriteName(type->name());
132                 temps.append(control()->namedType(name));
133             }
134         }
135
136         virtual void visit(Function *type)
137         {
138             Function *funTy = control()->newFunction(0, 0);
139             funTy->copy(type);
140             funTy->setConst(type->isConst());
141             funTy->setVolatile(type->isVolatile());
142
143             funTy->setName(rewrite->rewriteName(type->name()));
144
145             funTy->setReturnType(rewrite->rewriteType(type->returnType()));
146
147             for (unsigned i = 0; i < type->argumentCount(); ++i) {
148                 Symbol *arg = type->argumentAt(i);
149
150                 Argument *newArg = control()->newArgument(0, 0);
151                 newArg->copy(arg);
152                 newArg->setName(rewrite->rewriteName(arg->name()));
153                 newArg->setType(rewrite->rewriteType(arg->type()));
154
155                 funTy->addMember(newArg);
156             }
157
158             temps.append(funTy);
159         }
160
161         virtual void visit(Namespace *type)
162         {
163             qWarning() << Q_FUNC_INFO;
164             temps.append(type);
165         }
166
167         virtual void visit(Class *type)
168         {
169             qWarning() << Q_FUNC_INFO;
170             temps.append(type);
171         }
172
173         virtual void visit(Enum *type)
174         {
175             qWarning() << Q_FUNC_INFO;
176             temps.append(type);
177         }
178
179         virtual void visit(ForwardClassDeclaration *type)
180         {
181             qWarning() << Q_FUNC_INFO;
182             temps.append(type);
183         }
184
185         virtual void visit(ObjCClass *type)
186         {
187             qWarning() << Q_FUNC_INFO;
188             temps.append(type);
189         }
190
191         virtual void visit(ObjCProtocol *type)
192         {
193             qWarning() << Q_FUNC_INFO;
194             temps.append(type);
195         }
196
197         virtual void visit(ObjCMethod *type)
198         {
199             qWarning() << Q_FUNC_INFO;
200             temps.append(type);
201         }
202
203         virtual void visit(ObjCForwardClassDeclaration *type)
204         {
205             qWarning() << Q_FUNC_INFO;
206             temps.append(type);
207         }
208
209         virtual void visit(ObjCForwardProtocolDeclaration *type)
210         {
211             qWarning() << Q_FUNC_INFO;
212             temps.append(type);
213         }
214
215     };
216
217     class RewriteName: public NameVisitor
218     {
219         Rewrite *rewrite;
220         QList<const Name *> temps;
221
222         Control *control() const
223         { return rewrite->control; }
224
225         const Identifier *identifier(const Identifier *other) const
226         {
227             if (! other)
228                 return 0;
229
230             return control()->identifier(other->chars(), other->size());
231         }
232
233     public:
234         RewriteName(Rewrite *r): rewrite(r) {}
235
236         const Name *operator()(const Name *name)
237         {
238             if (! name)
239                 return 0;
240
241             accept(name);
242             return temps.takeLast();
243         }
244
245         virtual void visit(const QualifiedNameId *name)
246         {
247             const Name *base = rewrite->rewriteName(name->base());
248             const Name *n = rewrite->rewriteName(name->name());
249             temps.append(control()->qualifiedNameId(base, n));
250         }
251
252         virtual void visit(const Identifier *name)
253         {
254             temps.append(control()->identifier(name->chars(), name->size()));
255         }
256
257         virtual void visit(const TemplateNameId *name)
258         {
259             QVarLengthArray<FullySpecifiedType, 8> args(name->templateArgumentCount());
260             for (unsigned i = 0; i < name->templateArgumentCount(); ++i)
261                 args[i] = rewrite->rewriteType(name->templateArgumentAt(i));
262             temps.append(control()->templateNameId(identifier(name->identifier()), args.data(), args.size()));
263         }
264
265         virtual void visit(const DestructorNameId *name)
266         {
267             temps.append(control()->destructorNameId(identifier(name->identifier())));
268         }
269
270         virtual void visit(const OperatorNameId *name)
271         {
272             temps.append(control()->operatorNameId(name->kind()));
273         }
274
275         virtual void visit(const ConversionNameId *name)
276         {
277             FullySpecifiedType ty = rewrite->rewriteType(name->type());
278             temps.append(control()->conversionNameId(ty));
279         }
280
281         virtual void visit(const SelectorNameId *name)
282         {
283             QVarLengthArray<const Name *, 8> names(name->nameCount());
284             for (unsigned i = 0; i < name->nameCount(); ++i)
285                 names[i] = rewrite->rewriteName(name->nameAt(i));
286             temps.append(control()->selectorNameId(names.constData(), names.size(), name->hasArguments()));
287         }
288     };
289
290 public: // attributes
291     Control *control;
292     SubstitutionEnvironment *env;
293     RewriteType rewriteType;
294     RewriteName rewriteName;
295 };
296
297 SubstitutionEnvironment::SubstitutionEnvironment()
298     : _scope(0)
299 {
300 }
301
302 FullySpecifiedType SubstitutionEnvironment::apply(const Name *name, Rewrite *rewrite) const
303 {
304     if (name) {
305         for (int index = _substs.size() - 1; index != -1; --index) {
306             const Substitution *subst = _substs.at(index);
307
308             FullySpecifiedType ty = subst->apply(name, rewrite);
309             if (! ty->isUndefinedType())
310                 return ty;
311         }
312     }
313
314     return FullySpecifiedType();
315 }
316
317 void SubstitutionEnvironment::enter(Substitution *subst)
318 {
319     _substs.append(subst);
320 }
321
322 void SubstitutionEnvironment::leave()
323 {
324     _substs.removeLast();
325 }
326
327 Scope *SubstitutionEnvironment::scope() const
328 {
329     return _scope;
330 }
331
332 Scope *SubstitutionEnvironment::switchScope(Scope *scope)
333 {
334     Scope *previous = _scope;
335     _scope = scope;
336     return previous;
337 }
338
339 const LookupContext &SubstitutionEnvironment::context() const
340 {
341     return _context;
342 }
343
344 void SubstitutionEnvironment::setContext(const LookupContext &context)
345 {
346     _context = context;
347 }
348
349 SubstitutionMap::SubstitutionMap()
350 {
351
352 }
353
354 SubstitutionMap::~SubstitutionMap()
355 {
356
357 }
358
359 void SubstitutionMap::bind(const Name *name, const FullySpecifiedType &ty)
360 {
361     _map.append(qMakePair(name, ty));
362 }
363
364 FullySpecifiedType SubstitutionMap::apply(const Name *name, Rewrite *) const
365 {
366     for (int n = _map.size() - 1; n != -1; --n) {
367         const QPair<const Name *, FullySpecifiedType> &p = _map.at(n);
368
369         if (name->isEqualTo(p.first))
370             return p.second;
371     }
372
373     return FullySpecifiedType();
374 }
375
376
377 UseQualifiedNames::UseQualifiedNames()
378 {
379
380 }
381
382 UseQualifiedNames::~UseQualifiedNames()
383 {
384
385 }
386
387 FullySpecifiedType UseQualifiedNames::apply(const Name *name, Rewrite *rewrite) const
388 {
389     SubstitutionEnvironment *env = rewrite->env;
390     Scope *scope = env->scope();
391
392     if (name->isQualifiedNameId() || name->isTemplateNameId())
393         return FullySpecifiedType();
394
395     if (! scope)
396         return FullySpecifiedType();
397
398     const LookupContext &context = env->context();
399     Control *control = rewrite->control;
400
401     const QList<LookupItem> results = context.lookup(name, scope);
402     foreach (const LookupItem &r, results) {
403         if (Symbol *d = r.declaration()) {
404             const Name *n = 0;
405             foreach (const Name *c,  LookupContext::fullyQualifiedName(d)) {
406                 if (! n)
407                     n = c;
408                 else
409                     n = control->qualifiedNameId(n, c);
410             }
411
412             return control->namedType(n);
413         }
414
415         return r.type();
416     }
417
418     return FullySpecifiedType();
419 }
420
421
422 FullySpecifiedType rewriteType(const FullySpecifiedType &type,
423                                SubstitutionEnvironment *env,
424                                Control *control)
425 {
426     Rewrite rewrite(control, env);
427     return rewrite.rewriteType(type);
428 }
429
430 const Name *rewriteName(const Name *name,
431                         SubstitutionEnvironment *env,
432                         Control *control)
433 {
434     Rewrite rewrite(control, env);
435     return rewrite.rewriteName(name);
436 }
437
438 // Simplify complicated STL template types,
439 // such as 'std::basic_string<char,std::char_traits<char>,std::allocator<char> >'
440 // -> 'std::string' and helpers.
441
442 static QString chopConst(QString type)
443 {
444    while (1) {
445         if (type.startsWith(QLatin1String("const")))
446             type = type.mid(5);
447         else if (type.startsWith(QLatin1Char(' ')))
448             type = type.mid(1);
449         else if (type.endsWith(QLatin1String("const")))
450             type.chop(5);
451         else if (type.endsWith(QLatin1Char(' ')))
452             type.chop(1);
453         else
454             break;
455     }
456     return type;
457 }
458
459 static inline QRegExp stdStringRegExp(const QString &charType)
460 {
461     QString rc = QLatin1String("basic_string<");
462     rc += charType;
463     rc += QLatin1String(",[ ]?std::char_traits<");
464     rc += charType;
465     rc += QLatin1String(">,[ ]?std::allocator<");
466     rc += charType;
467     rc += QLatin1String("> >");
468     const QRegExp re(rc);
469     Q_ASSERT(re.isValid());
470     return re;
471 }
472
473 // Simplify string types in a type
474 // 'std::set<std::basic_string<char... > >' -> std::set<std::string>'
475 static inline void simplifyStdString(const QString &charType, const QString &replacement,
476                                      QString *type)
477 {
478     QRegExp stringRegexp = stdStringRegExp(charType);
479     const int replacementSize = replacement.size();
480     for (int pos = 0; pos < type->size(); ) {
481         // Check next match
482         const int matchPos = stringRegexp.indexIn(*type, pos);
483         if (matchPos == -1)
484             break;
485         const int matchedLength = stringRegexp.matchedLength();
486         type->replace(matchPos, matchedLength, replacement);
487         pos = matchPos + replacementSize;
488         // If we were inside an 'allocator<std::basic_string..char > >'
489         // kill the following blank -> 'allocator<std::string>'
490         if (pos + 1 < type->size() && type->at(pos) == QLatin1Char(' ')
491                 && type->at(pos + 1) == QLatin1Char('>'))
492             type->remove(pos, 1);
493     }
494 }
495
496 // Fix 'std::allocator<std::string >' -> 'std::allocator<std::string>',
497 // which can happen when replacing/simplifying
498 static inline QString fixNestedTemplates(QString s)
499 {
500     const int size = s.size();
501     if (size > 3
502             && s.at(size - 1) == QLatin1Char('>')
503             && s.at(size - 2) == QLatin1Char(' ')
504             && s.at(size - 3) != QLatin1Char('>'))
505             s.remove(size - 2, 1);
506     return s;
507 }
508
509 CPLUSPLUS_EXPORT QString simplifySTLType(const QString &typeIn)
510 {
511     QString type = typeIn;
512     if (type.startsWith("class ")) // MSVC prepends class,struct
513         type.remove(0, 6);
514     if (type.startsWith("struct "))
515         type.remove(0, 7);
516
517     type.replace(QLatin1Char('*'), QLatin1Char('@'));
518
519     for (int i = 0; i < 10; ++i) {
520         int start = type.indexOf("std::allocator<");
521         if (start == -1)
522             break;
523         // search for matching '>'
524         int pos;
525         int level = 0;
526         for (pos = start + 12; pos < type.size(); ++pos) {
527             int c = type.at(pos).unicode();
528             if (c == '<') {
529                 ++level;
530             } else if (c == '>') {
531                 --level;
532                 if (level == 0)
533                     break;
534             }
535         }
536         const QString alloc = fixNestedTemplates(type.mid(start, pos + 1 - start).trimmed());
537         const QString inner = fixNestedTemplates(alloc.mid(15, alloc.size() - 16).trimmed());
538         if (inner == QLatin1String("char")) { // std::string
539             simplifyStdString(QLatin1String("char"), QLatin1String("string"), &type);
540         } else if (inner == QLatin1String("wchar_t")) { // std::wstring
541             simplifyStdString(QLatin1String("wchar_t"), QLatin1String("wstring"), &type);
542         } else if (inner == QLatin1String("unsigned short")) { // std::wstring/MSVC
543             simplifyStdString(QLatin1String("unsigned short"), QLatin1String("wstring"), &type);
544         }
545         // std::vector, std::deque, std::list
546         const QRegExp re1(QString::fromLatin1("(vector|list|deque)<%1, ?%2\\s*>").arg(inner, alloc));
547         Q_ASSERT(re1.isValid());
548         if (re1.indexIn(type) != -1)
549             type.replace(re1.cap(0), QString::fromLatin1("%1<%2>").arg(re1.cap(1), inner));
550
551         // std::stack
552         QRegExp stackRE(QString::fromLatin1("stack<%1, ?std::deque<%2> >").arg(inner, inner));
553         stackRE.setMinimal(true);
554         Q_ASSERT(stackRE.isValid());
555         if (stackRE.indexIn(type) != -1)
556             type.replace(stackRE.cap(0), QString::fromLatin1("stack<%1>").arg(inner));
557
558         // std::set
559         QRegExp setRE(QString::fromLatin1("set<%1, ?std::less<%2>, ?%3\\s*>").arg(inner, inner, alloc));
560         setRE.setMinimal(true);
561         Q_ASSERT(setRE.isValid());
562         if (setRE.indexIn(type) != -1)
563             type.replace(setRE.cap(0), QString::fromLatin1("set<%1>").arg(inner));
564
565         // std::map
566         if (inner.startsWith("std::pair<")) {
567             // search for outermost ',', split key and value
568             int pos;
569             int level = 0;
570             for (pos = 10; pos < inner.size(); ++pos) {
571                 int c = inner.at(pos).unicode();
572                 if (c == '<')
573                     ++level;
574                 else if (c == '>')
575                     --level;
576                 else if (c == ',' && level == 0)
577                     break;
578             }
579             const QString key = chopConst(inner.mid(10, pos - 10));
580             // Get value: MSVC: 'pair<a const ,b>', gcc: 'pair<const a, b>'
581             if (inner.at(++pos) == QLatin1Char(' '))
582                 pos++;
583             QString value = inner.mid(pos, inner.size() - pos - 1).trimmed();
584             QRegExp mapRE1(QString("map<%1, ?%2, ?std::less<%3 ?>, ?%4\\s*>")
585                 .arg(key, value, key, alloc));
586             mapRE1.setMinimal(true);
587             Q_ASSERT(mapRE1.isValid());
588             if (mapRE1.indexIn(type) != -1) {
589                 type.replace(mapRE1.cap(0), QString("map<%1, %2>").arg(key, value));
590             } else {
591                 QRegExp mapRE2(QString("map<const %1, ?%2, ?std::less<const %3>, ?%4\\s*>")
592                     .arg(key, value, key, alloc));
593                 mapRE2.setMinimal(true);
594                 if (mapRE2.indexIn(type) != -1) {
595                     type.replace(mapRE2.cap(0), QString("map<const %1, %2>").arg(key, value));
596                 }
597             }
598         }
599     }
600     type.replace(QLatin1Char('@'), QLatin1Char('*'));
601     type.replace(QLatin1String(" >"), QLatin1String(">"));
602     return type;
603 }
604
605 } // namespace CPlusPlus