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 #pragma once
27 
28 #include "CppDocument.h"
29 #include "LookupItem.h"
30 #include "AlreadyConsideredClassContainer.h"
31 
32 #include <cplusplus/FullySpecifiedType.h>
33 #include <cplusplus/Type.h>
34 #include <cplusplus/SymbolVisitor.h>
35 #include <cplusplus/Control.h>
36 #include <cplusplus/Name.h>
37 
38 #include <QSet>
39 #include <QMap>
40 
41 #include <functional>
42 #include <map>
43 #include <unordered_map>
44 
45 namespace CPlusPlus {
46 
47 namespace Internal {
48 struct FullyQualifiedName
49 {
50     QList<const Name *> fqn;
51 
FullyQualifiedNameFullyQualifiedName52     FullyQualifiedName(const QList<const Name *> &fqn)
53         : fqn(fqn)
54     {}
55 };
56 } // namespace Internal;
57 
58 class CreateBindings;
59 
60 class CPLUSPLUS_EXPORT ClassOrNamespace
61 {
62     Q_DISABLE_COPY(ClassOrNamespace)
63 
64     ClassOrNamespace(CreateBindings *factory, ClassOrNamespace *parent);
65 
66 public:
67     ~ClassOrNamespace();
68 
69     const TemplateNameId *templateId() const;
70     ClassOrNamespace *instantiationOrigin() const;
71 
72     ClassOrNamespace *parent() const;
73     QList<ClassOrNamespace *> usings() const;
74     QList<Enum *> unscopedEnums() const;
75     QList<Symbol *> symbols() const;
76 
77     ClassOrNamespace *globalNamespace() const;
78 
79     QList<LookupItem> lookup(const Name *name);
80     QList<LookupItem> find(const Name *name);
81 
82     ClassOrNamespace *lookupType(const Name *name);
83     ClassOrNamespace *lookupType(const Name *name, Block *block);
84     ClassOrNamespace *findType(const Name *name);
85     ClassOrNamespace *findBlock(Block *block);
86     ClassOrNamespace *getNested(const Name *name);
87 
88     Symbol *lookupInScope(const QList<const Name *> &fullName);
89 
90     /// The class this ClassOrNamespace is based on.
rootClass()91     Class *rootClass() const { return _rootClass; }
92 
93 private:
94     typedef std::unordered_map<const Name *, ClassOrNamespace *, Name::Hash, Name::Equals> Table;
95     typedef std::unordered_map<const TemplateNameId *, ClassOrNamespace *, TemplateNameId::Hash, TemplateNameId::Equals> TemplateNameIdTable;
96     typedef QHash<const AnonymousNameId *, ClassOrNamespace *> Anonymouses;
97 
98     /// \internal
99     void flush();
100 
101     /// \internal
102     ClassOrNamespace *findOrCreateType(const Name *name, ClassOrNamespace *origin = nullptr,
103                                        Class *clazz = nullptr);
104 
105     ClassOrNamespace *findOrCreateNestedAnonymousType(const AnonymousNameId *anonymousNameId);
106 
107     void addTodo(Symbol *symbol);
108     void addSymbol(Symbol *symbol);
109     void addUnscopedEnum(Enum *e);
110     void addUsing(ClassOrNamespace *u);
111     void addNestedType(const Name *alias, ClassOrNamespace *e);
112 
113     QList<LookupItem> lookup_helper(const Name *name, bool searchInEnclosingScope);
114 
115     void lookup_helper(const Name *name, ClassOrNamespace *binding,
116                        QList<LookupItem> *result,
117                        QSet<ClassOrNamespace *> *processed,
118                        const TemplateNameId *templateId);
119 
120     ClassOrNamespace *lookupType_helper(const Name *name, QSet<ClassOrNamespace *> *processed,
121                                         bool searchInEnclosingScope, ClassOrNamespace *origin);
122 
123     ClassOrNamespace *findBlock_helper(Block *block, QSet<ClassOrNamespace *> *processed,
124                                        bool searchInEnclosingScope);
125 
126     ClassOrNamespace *nestedType(const Name *name, QSet<ClassOrNamespace *> *processed,
127                                  ClassOrNamespace *origin);
128 
129     void instantiateNestedClasses(ClassOrNamespace *enclosingTemplateClass,
130                                   Clone &cloner,
131                                   Subst &subst,
132                                   ClassOrNamespace *enclosingTemplateClassInstantiation);
133     ClassOrNamespace *findSpecialization(const TemplateNameId *templId,
134                                          const TemplateNameIdTable &specializations);
135 
136     CreateBindings *_factory;
137     ClassOrNamespace *_parent;
138     QList<Symbol *> _symbols;
139     QList<ClassOrNamespace *> _usings;
140     Table _classOrNamespaces;
141     QHash<Block *, ClassOrNamespace *> _blocks;
142     QList<Enum *> _enums;
143     QList<Symbol *> _todo;
144     QSharedPointer<Control> _control;
145     TemplateNameIdTable _specializations;
146     QMap<const TemplateNameId *, ClassOrNamespace *> _instantiations;
147     Anonymouses _anonymouses;
148     QSet<const AnonymousNameId *> _declaredOrTypedefedAnonymouses;
149 
150     QHash<Internal::FullyQualifiedName, Symbol *> *_scopeLookupCache;
151 
152     // it's an instantiation.
153     const TemplateNameId *_templateId;
154     ClassOrNamespace *_instantiationOrigin;
155 
156     AlreadyConsideredClassContainer<Class> _alreadyConsideredClasses;
157     AlreadyConsideredClassContainer<TemplateNameId> _alreadyConsideredTemplates;
158 
159     Class *_rootClass;
160 
161     class NestedClassInstantiator
162     {
163     public:
NestedClassInstantiator(CreateBindings * factory,Clone & cloner,Subst & subst)164         NestedClassInstantiator(CreateBindings *factory, Clone &cloner, Subst &subst)
165             : _factory(factory)
166             , _cloner(cloner)
167             , _subst(subst)
168         {}
169         void instantiate(ClassOrNamespace *enclosingTemplateClass,
170                          ClassOrNamespace *enclosingTemplateClassInstantiation);
171     private:
172         bool isInstantiateNestedClassNeeded(const QList<Symbol *> &symbols) const;
173         bool containsTemplateType(Declaration *declaration) const;
174         bool containsTemplateType(Function *function) const;
175         NamedType *findNamedType(Type *memberType) const;
176 
177         QSet<ClassOrNamespace *> _alreadyConsideredNestedClassInstantiations;
178         CreateBindings *_factory;
179         Clone &_cloner;
180         Subst &_subst;
181     };
182 
183 public:
184     const Name *_name; // For debug
185 
186     friend class CreateBindings;
187 };
188 
189 class CPLUSPLUS_EXPORT CreateBindings: protected SymbolVisitor
190 {
191     Q_DISABLE_COPY(CreateBindings)
192 
193 public:
194     CreateBindings(Document::Ptr thisDocument, const Snapshot &snapshot);
195     virtual ~CreateBindings();
196 
197     /// Returns the binding for the global namespace.
198     ClassOrNamespace *globalNamespace() const;
199 
200     /// Finds the binding associated to the given symbol.
201     ClassOrNamespace *lookupType(Symbol *symbol, ClassOrNamespace *enclosingBinding = nullptr);
202     ClassOrNamespace *lookupType(const QList<const Name *> &path,
203                                  ClassOrNamespace *enclosingBinding = nullptr);
204 
205     /// Returns the Control that must be used to create temporary symbols.
206     /// \internal
control()207     QSharedPointer<Control> control() const
208     { return _control; }
209 
expandTemplates()210     bool expandTemplates() const
211     { return _expandTemplates; }
setExpandTemplates(bool expandTemplates)212     void setExpandTemplates(bool expandTemplates)
213     { _expandTemplates = expandTemplates; }
214 
215     /// Searches in \a scope for symbols with the given \a name.
216     /// Store the result in \a results.
217     /// \internal
218     void lookupInScope(const Name *name, Scope *scope, QList<LookupItem> *result,
219                             const TemplateNameId *templateId, ClassOrNamespace *binding);
220 
221     /// Create bindings for the symbols reachable from \a rootSymbol.
222     /// \internal
223     void process(Symbol *rootSymbol, ClassOrNamespace *classOrNamespace);
224 
225     /// Create an empty ClassOrNamespace binding with the given \a parent.
226     /// \internal
227     ClassOrNamespace *allocClassOrNamespace(ClassOrNamespace *parent);
228 
229 protected:
230     using SymbolVisitor::visit;
231 
232     /// Change the current ClassOrNamespace binding.
233     ClassOrNamespace *switchCurrentClassOrNamespace(ClassOrNamespace *classOrNamespace);
234 
235     /// Enters the ClassOrNamespace binding associated with the given \a symbol.
236     ClassOrNamespace *enterClassOrNamespaceBinding(Symbol *symbol);
237 
238     /// Enters a ClassOrNamespace binding for the given \a symbol in the global
239     /// namespace binding.
240     ClassOrNamespace *enterGlobalClassOrNamespace(Symbol *symbol);
241 
242     /// Creates bindings for the given \a document.
243     void process(Document::Ptr document);
244 
245     /// Creates bindings for the symbols reachable from the \a root symbol.
246     void process(Symbol *root);
247 
248     bool visit(Template *templ) override;
249     bool visit(Namespace *ns) override;
250     bool visit(Class *klass) override;
251     bool visit(ForwardClassDeclaration *klass) override;
252     bool visit(Enum *e) override;
253     bool visit(Declaration *decl) override;
254     bool visit(Function *function) override;
255     bool visit(Block *block) override;
256 
257     bool visit(BaseClass *b) override;
258     bool visit(UsingNamespaceDirective *u) override;
259     bool visit(UsingDeclaration *u) override;
260     bool visit(NamespaceAlias *a) override;
261 
262     bool visit(ObjCClass *klass) override;
263     bool visit(ObjCBaseClass *b) override;
264     bool visit(ObjCForwardClassDeclaration *klass) override;
265     bool visit(ObjCProtocol *proto) override;
266     bool visit(ObjCBaseProtocol *b) override;
267     bool visit(ObjCForwardProtocolDeclaration *proto) override;
268     bool visit(ObjCMethod *) override;
269 
270 private:
271     Symbol *instantiateTemplateFunction(const Name *instantiationName,
272                                         Template *specialization) const;
273 
274     Snapshot _snapshot;
275     QSharedPointer<Control> _control;
276     QSet<Namespace *> _processed;
277     QList<ClassOrNamespace *> _entities;
278     ClassOrNamespace *_globalNamespace;
279     ClassOrNamespace *_currentClassOrNamespace;
280     bool _expandTemplates;
281 };
282 
283 class CPLUSPLUS_EXPORT LookupContext
284 {
285 public:
286     LookupContext();
287 
288     LookupContext(Document::Ptr thisDocument,
289                   const Snapshot &snapshot);
290 
291     LookupContext(Document::Ptr expressionDocument,
292                   Document::Ptr thisDocument,
293                   const Snapshot &snapshot,
294                   QSharedPointer<CreateBindings> bindings = QSharedPointer<CreateBindings>());
295 
296     LookupContext(const LookupContext &other);
297     LookupContext &operator = (const LookupContext &other);
298 
299     Document::Ptr expressionDocument() const;
300     Document::Ptr thisDocument() const;
301     Document::Ptr document(const QString &fileName) const;
302     Snapshot snapshot() const;
303 
304     ClassOrNamespace *globalNamespace() const;
305 
306     QList<LookupItem> lookup(const Name *name, Scope *scope) const;
307     ClassOrNamespace *lookupType(const Name *name, Scope *scope,
308                                  ClassOrNamespace *enclosingBinding = nullptr,
309                                  QSet<const Declaration *> typedefsBeingResolved
310                                     = QSet<const Declaration *>()) const;
311     ClassOrNamespace *lookupType(Symbol *symbol,
312                                  ClassOrNamespace *enclosingBinding = nullptr) const;
313     ClassOrNamespace *lookupParent(Symbol *symbol) const;
314 
315     /// \internal
bindings()316     QSharedPointer<CreateBindings> bindings() const
317     { return _bindings; }
318 
319     enum InlineNamespacePolicy { ShowInlineNamespaces, HideInlineNamespaces };
320     static QList<const Name *> fullyQualifiedName(
321         Symbol *symbol, InlineNamespacePolicy policy = ShowInlineNamespaces);
322     static QList<const Name *> path(Symbol *symbol,
323                                     InlineNamespacePolicy policy = ShowInlineNamespaces);
324 
325     static const Name *minimalName(Symbol *symbol, ClassOrNamespace *target, Control *control);
326 
setExpandTemplates(bool expandTemplates)327     void setExpandTemplates(bool expandTemplates)
328     {
329         if (_bindings)
330             _bindings->setExpandTemplates(expandTemplates);
331         m_expandTemplates = expandTemplates;
332     }
333 
334 private:
335     QList<LookupItem> lookupByUsing(const Name *name, ClassOrNamespace *bindingScope) const;
336 
337     // The current expression.
338     Document::Ptr _expressionDocument;
339 
340     // The current document.
341     Document::Ptr _thisDocument;
342 
343     // All documents.
344     Snapshot _snapshot;
345 
346     // Bindings
347     QSharedPointer<CreateBindings> _bindings;
348 
349     bool m_expandTemplates;
350 };
351 
352 bool CPLUSPLUS_EXPORT compareFullyQualifiedName(const QList<const Name *> &path,
353                                                 const QList<const Name *> &other);
354 
355 
356 } // namespace CPlusPlus
357