1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #include "DeprecatedGenTemplateInstance.h"
27 #include "Overview.h"
28 
29 #include <cplusplus/Control.h>
30 #include <cplusplus/Scope.h>
31 #include <cplusplus/Names.h>
32 #include <cplusplus/Symbols.h>
33 #include <cplusplus/CoreTypes.h>
34 #include <cplusplus/Literals.h>
35 
36 #include <QVarLengthArray>
37 #include <QDebug>
38 
39 using namespace CPlusPlus;
40 
41 namespace {
42 
43 class ApplySubstitution
44 {
45 public:
46     ApplySubstitution(Control *control, Symbol *symbol, const DeprecatedGenTemplateInstance::Substitution &substitution);
47     ~ApplySubstitution();
48 
control() const49     inline Control *control() const { return _control; }
50 
51     FullySpecifiedType apply(const Name *name);
52     FullySpecifiedType apply(const FullySpecifiedType &type);
53 
54     int findSubstitution(const Identifier *id) const;
55     FullySpecifiedType applySubstitution(int index) const;
56 
57 private:
58     class ApplyToType: protected TypeVisitor
59     {
60     public:
ApplyToType(ApplySubstitution * q)61         ApplyToType(ApplySubstitution *q)
62             : q(q) {}
63 
operator ()(const FullySpecifiedType & ty)64         FullySpecifiedType operator()(const FullySpecifiedType &ty)
65         {
66             FullySpecifiedType previousType = switchType(ty);
67             accept(ty.type());
68             return switchType(previousType);
69         }
70 
71     protected:
72         using TypeVisitor::visit;
73 
control() const74         Control *control() const
75         { return q->control(); }
76 
switchType(const FullySpecifiedType & type)77         FullySpecifiedType switchType(const FullySpecifiedType &type)
78         {
79             FullySpecifiedType previousType = _type;
80             _type = type;
81             return previousType;
82         }
83 
visit(VoidType *)84         void visit(VoidType *) override
85         {
86             // nothing to do
87         }
88 
visit(IntegerType *)89         void visit(IntegerType *) override
90         {
91             // nothing to do
92         }
93 
visit(FloatType *)94         void visit(FloatType *) override
95         {
96             // nothing to do
97         }
98 
visit(PointerToMemberType *)99         void visit(PointerToMemberType *) override
100         {
101             qDebug() << Q_FUNC_INFO; // ### TODO
102         }
103 
visit(PointerType * ptrTy)104         void visit(PointerType *ptrTy) override
105         {
106             _type.setType(control()->pointerType(q->apply(ptrTy->elementType())));
107         }
108 
visit(ReferenceType * refTy)109         void visit(ReferenceType *refTy) override
110         {
111             _type.setType(control()->referenceType(q->apply(refTy->elementType()), refTy->isRvalueReference()));
112         }
113 
visit(ArrayType * arrayTy)114         void visit(ArrayType *arrayTy) override
115         {
116             _type.setType(control()->arrayType(q->apply(arrayTy->elementType()), arrayTy->size()));
117         }
118 
visit(NamedType * ty)119         void visit(NamedType *ty) override
120         {
121             FullySpecifiedType n = q->apply(ty->name());
122             _type.setType(n.type());
123         }
124 
visit(Function * funTy)125         void visit(Function *funTy) override
126         {
127             Function *fun = control()->newFunction(/*sourceLocation=*/ 0, funTy->name());
128             fun->setEnclosingScope(funTy->enclosingScope());
129             fun->setConst(funTy->isConst());
130             fun->setVolatile(funTy->isVolatile());
131             fun->setVirtual(funTy->isVirtual());
132             fun->setOverride(funTy->isOverride());
133             fun->setFinal(funTy->isFinal());
134             fun->setAmbiguous(funTy->isAmbiguous());
135             fun->setVariadic(funTy->isVariadic());
136 
137             fun->setReturnType(q->apply(funTy->returnType()));
138 
139             for (int i = 0, argc = funTy->argumentCount(); i < argc; ++i) {
140                 Argument *originalArgument = funTy->argumentAt(i)->asArgument();
141                 Argument *arg = control()->newArgument(/*sourceLocation*/ 0,
142                                                        originalArgument->name());
143 
144                 arg->setType(q->apply(originalArgument->type()));
145                 arg->setInitializer(originalArgument->initializer());
146                 fun->addMember(arg);
147             }
148 
149             _type.setType(fun);
150         }
151 
visit(Namespace *)152         void visit(Namespace *) override
153         {
154             qDebug() << Q_FUNC_INFO;
155         }
156 
visit(Class *)157         void visit(Class *) override
158         {
159             qDebug() << Q_FUNC_INFO;
160         }
161 
visit(Enum *)162         void visit(Enum *) override
163         {
164             qDebug() << Q_FUNC_INFO;
165         }
166 
visit(ForwardClassDeclaration *)167         void visit(ForwardClassDeclaration *) override
168         {
169             qDebug() << Q_FUNC_INFO;
170         }
171 
visit(ObjCClass *)172         void visit(ObjCClass *) override
173         {
174             qDebug() << Q_FUNC_INFO;
175         }
176 
visit(ObjCProtocol *)177         void visit(ObjCProtocol *) override
178         {
179             qDebug() << Q_FUNC_INFO;
180         }
181 
visit(ObjCMethod *)182         void visit(ObjCMethod *) override
183         {
184             qDebug() << Q_FUNC_INFO;
185         }
186 
visit(ObjCForwardClassDeclaration *)187         void visit(ObjCForwardClassDeclaration *) override
188         {
189             qDebug() << Q_FUNC_INFO;
190         }
191 
visit(ObjCForwardProtocolDeclaration *)192         void visit(ObjCForwardProtocolDeclaration *) override
193         {
194             qDebug() << Q_FUNC_INFO;
195         }
196 
197     private:
198         ApplySubstitution *q;
199         FullySpecifiedType _type;
200         QHash<Symbol *, FullySpecifiedType> _processed;
201     };
202 
203     class ApplyToName: protected NameVisitor
204     {
205     public:
ApplyToName(ApplySubstitution * q)206         ApplyToName(ApplySubstitution *q): q(q) {}
207 
operator ()(const Name * name)208         FullySpecifiedType operator()(const Name *name)
209         {
210             FullySpecifiedType previousType = switchType(FullySpecifiedType());
211             accept(name);
212             return switchType(previousType);
213         }
214 
215     protected:
control() const216         Control *control() const
217         { return q->control(); }
218 
findSubstitution(const Identifier * id) const219         int findSubstitution(const Identifier *id) const
220         { return q->findSubstitution(id); }
221 
applySubstitution(int index) const222         FullySpecifiedType applySubstitution(int index) const
223         { return q->applySubstitution(index); }
224 
switchType(const FullySpecifiedType & type)225         FullySpecifiedType switchType(const FullySpecifiedType &type)
226         {
227             FullySpecifiedType previousType = _type;
228             _type = type;
229             return previousType;
230         }
231 
visit(const Identifier * name)232         void visit(const Identifier *name) override
233         {
234             int index = findSubstitution(name->identifier());
235 
236             if (index != -1)
237                 _type = applySubstitution(index);
238 
239             else
240                 _type = control()->namedType(name);
241         }
242 
visit(const TemplateNameId * name)243         void visit(const TemplateNameId *name) override
244         {
245             QVarLengthArray<TemplateArgument, 8> arguments(name->templateArgumentCount());
246             for (int i = 0; i < name->templateArgumentCount(); ++i) {
247                 FullySpecifiedType argTy = name->templateArgumentAt(i).type();
248                 arguments[i] = q->apply(argTy);
249             }
250 
251             const TemplateNameId *templId = control()->templateNameId(name->identifier(),
252                                                                       name->isSpecialization(),
253                                                                       arguments.data(),
254                                                                       arguments.size());
255             _type = control()->namedType(templId);
256         }
257 
instantiate(const Name * name)258         const Name *instantiate(const Name *name)
259         {
260             if (! name)
261                 return name;
262 
263             if (const Identifier *nameId = name->asNameId()) {
264                 const Identifier *id = control()->identifier(nameId->chars(), nameId->size());
265                 return id;
266 
267             } else if (const TemplateNameId *templId = name->asTemplateNameId()) {
268                 QVarLengthArray<TemplateArgument, 8> arguments(templId->templateArgumentCount());
269                 for (int templateArgIndex = 0; templateArgIndex < templId->templateArgumentCount();
270                      ++templateArgIndex) {
271                     FullySpecifiedType argTy = templId->templateArgumentAt(templateArgIndex).type();
272                     arguments[templateArgIndex] = q->apply(argTy);
273                 }
274                 const Identifier *id = control()->identifier(templId->identifier()->chars(),
275                                                                          templId->identifier()->size());
276                 return control()->templateNameId(id, templId->isSpecialization(), arguments.data(),
277                                                  arguments.size());
278 
279             } else if (const QualifiedNameId *qq = name->asQualifiedNameId()) {
280                 const Name *base = instantiate(qq->base());
281                 const Name *name = instantiate(qq->name());
282 
283                 return control()->qualifiedNameId(base, name);
284 
285             } else if (const OperatorNameId *op = name->asOperatorNameId()) {
286                 return control()->operatorNameId(op->kind());
287 
288             } else if (const ConversionNameId *c = name->asConversionNameId()) {
289                 FullySpecifiedType ty = q->apply(c->type());
290                 return control()->conversionNameId(ty);
291 
292             }
293 
294             return nullptr;
295         }
296 
visit(const QualifiedNameId * name)297         void visit(const QualifiedNameId *name) override
298         {
299             if (const Name *n = instantiate(name))
300                 _type = control()->namedType(n);
301         }
302 
visit(const DestructorNameId * name)303         void visit(const DestructorNameId *name) override
304         {
305             Overview oo;
306             qWarning() << "ignored name:" << oo.prettyName(name);
307         }
308 
visit(const OperatorNameId * name)309         void visit(const OperatorNameId *name) override
310         {
311             Overview oo;
312             qWarning() << "ignored name:" << oo.prettyName(name);
313         }
314 
visit(const ConversionNameId * name)315         void visit(const ConversionNameId *name) override
316         {
317             Overview oo;
318             qWarning() << "ignored name:" << oo.prettyName(name);
319         }
320 
visit(const SelectorNameId * name)321         void visit(const SelectorNameId *name) override
322         {
323             Overview oo;
324             qWarning() << "ignored name:" << oo.prettyName(name);
325         }
326 
327     private:
328         ApplySubstitution *q;
329         FullySpecifiedType _type;
330     };
331 
332 public: // attributes
333     Control *_control;
334     Symbol *symbol;
335     DeprecatedGenTemplateInstance::Substitution substitution;
336     ApplyToType applyToType;
337     ApplyToName applyToName;
338 };
339 
ApplySubstitution(Control * control,Symbol * symbol,const DeprecatedGenTemplateInstance::Substitution & substitution)340 ApplySubstitution::ApplySubstitution(Control *control, Symbol *symbol,
341                                      const DeprecatedGenTemplateInstance::Substitution &substitution)
342     : _control(control), symbol(symbol),
343       substitution(substitution),
344       applyToType(this), applyToName(this)
345 { }
346 
~ApplySubstitution()347 ApplySubstitution::~ApplySubstitution()
348 {
349 }
350 
apply(const Name * name)351 FullySpecifiedType ApplySubstitution::apply(const Name *name)
352 {
353     FullySpecifiedType ty = applyToName(name);
354     return ty;
355 }
356 
apply(const FullySpecifiedType & type)357 FullySpecifiedType ApplySubstitution::apply(const FullySpecifiedType &type)
358 {
359     FullySpecifiedType ty = applyToType(type);
360     return ty;
361 }
362 
findSubstitution(const Identifier * id) const363 int ApplySubstitution::findSubstitution(const Identifier *id) const
364 {
365     Q_ASSERT(id != nullptr);
366 
367     for (int index = 0; index < substitution.size(); ++index) {
368         QPair<const Identifier *, FullySpecifiedType> s = substitution.at(index);
369 
370         if (id->match(s.first))
371             return index;
372     }
373 
374     return -1;
375 }
376 
applySubstitution(int index) const377 FullySpecifiedType ApplySubstitution::applySubstitution(int index) const
378 {
379     Q_ASSERT(index != -1);
380     Q_ASSERT(index < substitution.size());
381 
382     return substitution.at(index).second;
383 }
384 
385 } // end of anonymous namespace
386 
DeprecatedGenTemplateInstance(QSharedPointer<Control> control,const Substitution & substitution)387 DeprecatedGenTemplateInstance::DeprecatedGenTemplateInstance(QSharedPointer<Control> control, const Substitution &substitution)
388     : _control(control),
389       _substitution(substitution)
390 { }
391 
gen(Symbol * symbol)392 FullySpecifiedType DeprecatedGenTemplateInstance::gen(Symbol *symbol)
393 {
394     ApplySubstitution o(_control.data(), symbol, _substitution);
395     return o.apply(symbol->type());
396 }
397 
instantiate(const Name * className,Symbol * candidate,QSharedPointer<Control> control)398 FullySpecifiedType DeprecatedGenTemplateInstance::instantiate(const Name *className, Symbol *candidate,
399                                                               QSharedPointer<Control> control)
400 {
401     if (className) {
402         if (const TemplateNameId *templId = className->asTemplateNameId()) {
403             if (Template *templ = candidate->enclosingTemplate()) {
404                 DeprecatedGenTemplateInstance::Substitution subst;
405 
406                 for (int i = 0; i < templId->templateArgumentCount(); ++i) {
407                     FullySpecifiedType templArgTy = templId->templateArgumentAt(i).type();
408 
409                     if (i < templ->templateParameterCount()) {
410                         const Name *templArgName = templ->templateParameterAt(i)->name();
411 
412                         if (templArgName && templArgName->identifier()) {
413                             const Identifier *templArgId = templArgName->identifier();
414                             subst.append(qMakePair(templArgId, templArgTy));
415                         }
416                     }
417                 }
418 
419                 DeprecatedGenTemplateInstance inst(control, subst);
420                 return inst.gen(candidate);
421             }
422         }
423     }
424     return candidate->type();
425 }
426