OSDN Git Service

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