~ubuntu-branches/debian/sid/kdevelop/sid

« back to all changes in this revision

Viewing changes to languages/cpp/cppduchain/cppducontext.h

  • Committer: Bazaar Package Importer
  • Author(s): Jeremy Lainé
  • Date: 2010-05-05 07:21:55 UTC
  • mfrom: (1.2.3 upstream) (5.1.2 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100505072155-h78lx19pu04sbhtn
Tags: 4:4.0.0-2
* Upload to unstable (Closes: #579947, #481832).
* Acknowledge obsolete NMU fixes (Closes: #562410, #546961).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is part of KDevelop
 
2
    Copyright 2007 David Nolden <david.nolden.kdevelop@art-master.de>
 
3
 
 
4
   This library is free software; you can redistribute it and/or
 
5
   modify it under the terms of the GNU Library General Public
 
6
   License version 2 as published by the Free Software Foundation.
 
7
 
 
8
   This library is distributed in the hope that it will be useful,
 
9
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
11
   Library General Public License for more details.
 
12
 
 
13
   You should have received a copy of the GNU Library General Public License
 
14
   along with this library; see the file COPYING.LIB.  If not, write to
 
15
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
16
   Boston, MA 02110-1301, USA.
 
17
*/
 
18
 
 
19
/*
 
20
 
 
21
Some mindmapping about how the template-system works:
 
22
 
 
23
While construction:
 
24
- Simplify: Template-parameters are types
 
25
- Within template-contexts, do not resolve any types. Instead create "virtual types" that will resolve the types when template-parameters are given.
 
26
 (DelayedType) - ready
 
27
 
 
28
 
 
29
 Later:
 
30
 - Searching instantiated template-class:
 
31
        - return virtual declaration
 
32
        - return virtual context (Change template-parameter-context to given template-arguments)
 
33
 - Searching IN instantiated template-class:
 
34
       - When searching local declarations:
 
35
         - Check whether they are already in the instantiated context, if yes return them
 
36
         - If not, Search in non-instantiated context(only for local declarations), then:
 
37
           - Copy & Change returned objects:
 
38
             - Resolve virtual types (DelayedType)
 
39
             - Change parent-context to virtual context
 
40
             - Change internal context, (create virtual, move set parent)
 
41
 
 
42
 - How template-parameters are resolved:
 
43
    - The DUContext's with type DUContext::Template get their template-parameter declarations instantiated and added locally. Then they will be found when resolving virtual types.
 
44
    - 
 
45
 
 
46
*/
 
47
 
 
48
#ifndef CPPDUCONTEXT_H
 
49
#define CPPDUCONTEXT_H
 
50
 
 
51
#include <language/duchain/ducontext.h>
 
52
 
 
53
#include <QSet>
 
54
#include <QMutex>
 
55
 
 
56
#include <language/duchain/abstractfunctiondeclaration.h>
 
57
#include <language/duchain/declaration.h>
 
58
#include <language/duchain/duchainlock.h>
 
59
#include <language/duchain/duchain.h>
 
60
#include <language/duchain/topducontext.h>
 
61
#include <language/duchain/classfunctiondeclaration.h>
 
62
#include <language/duchain/namespacealiasdeclaration.h>
 
63
#include "typeutils.h"
 
64
#include "cpptypes.h"
 
65
#include "cppduchain.h"
 
66
#include "templatedeclaration.h"
 
67
#include "expressionparser.h"
 
68
#include "cppdebughelper.h"
 
69
 
 
70
using namespace KDevelop;
 
71
 
 
72
namespace Cpp {
 
73
extern QMutex cppDuContextInstantiationsMutex;
 
74
 
 
75
    ///This class breaks up the logic of searching a declaration in C++, so QualifiedIdentifiers as well as AST-based lookup mechanisms can be used for searching
 
76
    class FindDeclaration {
 
77
      public:
 
78
        FindDeclaration( const DUContext* ctx, const TopDUContext* source, DUContext::SearchFlags flags, const SimpleCursor& position, AbstractType::Ptr dataType = AbstractType::Ptr() ) : m_context(ctx), m_source(source), m_flags(flags), m_position(position), m_dataType(dataType) {
 
79
          Q_ASSERT(m_source);
 
80
        }
 
81
        void openQualifiedIdentifier( bool isExplicitlyGlobal ) {
 
82
          QualifiedIdentifier i;
 
83
          i.setExplicitlyGlobal( isExplicitlyGlobal );
 
84
          StatePtr s(new State);
 
85
          s->identifier = i;
 
86
          m_states << s;
 
87
        }
 
88
 
 
89
        ///Can be used to just append a result that was computed outside. closeQualifiedIdentifier(...) must still be called.
 
90
        void openQualifiedIdentifier( const ExpressionEvaluationResult& result ) {
 
91
          StatePtr s(new State);
 
92
          s->expressionResult = result;
 
93
          s->result.clear();
 
94
          foreach(const DeclarationId& decl, result.allDeclarations)
 
95
          s->result << DeclarationPointer( decl.getDeclaration(const_cast<TopDUContext*>(topContext())) );
 
96
          
 
97
          m_states << s;
 
98
        }
 
99
 
 
100
        /**
 
101
         * After this was called, lastDeclarations(..) can be used to retrieve declarations of the qualified identifier.
 
102
         * The DUChain needs to be locked when this is called.
 
103
         * */
 
104
        void closeQualifiedIdentifier();
 
105
        /**
 
106
         * The identifier must not have template identifiers, those need to be added using openQualifiedIdentifier(..) and closeQualifiedIdentifier(..)
 
107
         * */
 
108
        void openIdentifier( const Identifier& identifier ) {
 
109
         m_states.top()->identifier.push(identifier);
 
110
        }
 
111
        /**
 
112
         * When closeIdentifier() is called, the last opened identifier is searched, and can be retrieved using lastDeclarations().
 
113
         * Returns false when the search should be stopped.
 
114
         * The DUChain needs to be locked when this is called.
 
115
         * @param isFinalIdentifier Whether the closed identifier the last one. Needed to know when to apply what search-flags.
 
116
         * */
 
117
        bool closeIdentifier(bool isFinalIdentifier);
 
118
 
 
119
        ///For debugging. Describes the last search context.
 
120
        QString describeLastContext() const {
 
121
          if( m_lastScopeContext ) {
 
122
            return "Context " + m_lastScopeContext->scopeIdentifier(true).toString() + QString(" from %1:%2").arg(m_lastScopeContext->url().str()).arg(m_lastScopeContext->range().start.line);
 
123
          } else {
 
124
            return QString("Global search with top-context %2").arg(topContext()->url().str());
 
125
          }
 
126
        }
 
127
 
 
128
        /**
 
129
         * Returns the Declarations found for the last closed qualified identifier.
 
130
         * 
 
131
         * */
 
132
        QList<DeclarationPointer> lastDeclarations() const {
 
133
          return m_lastDeclarations;
 
134
        }
 
135
 
 
136
        const TopDUContext* topContext() const {
 
137
          return m_source;
 
138
        }
 
139
        
 
140
        uint currentLength() const {
 
141
          return m_states.size();
 
142
        }
 
143
 
 
144
      private:
 
145
 
 
146
        ///Uses the instantiation-information from the context of decl as parent of templateArguments.
 
147
        Declaration* instantiateDeclaration( Declaration* decl, const InstantiationInformation& templateArguments ) const;
 
148
        
 
149
        struct State : public KShared {
 
150
          State() {
 
151
          }
 
152
          QualifiedIdentifier identifier; //identifier including eventual namespace prefix
 
153
          InstantiationInformation templateParameters;
 
154
 
 
155
          ///One of the following is filled
 
156
          QList<DeclarationPointer> result;
 
157
          ExpressionEvaluationResult expressionResult;
 
158
        };
 
159
        
 
160
        typedef KSharedPtr<State> StatePtr;
 
161
        
 
162
        QStack<StatePtr> m_states;
 
163
        const DUContext* m_context;
 
164
        const TopDUContext* m_source;
 
165
        DUContext::SearchFlags m_flags;
 
166
        QList<DeclarationPointer> m_lastDeclarations;
 
167
        SimpleCursor m_position;
 
168
        AbstractType::Ptr m_dataType;
 
169
 
 
170
        DUContextPointer m_lastScopeContext; //For debugging, last context in which we searched
 
171
    };
 
172
 
 
173
/**
 
174
 * This is a du-context template that wraps the c++-specific logic around existing DUContext-derived classes.
 
175
 * In practice this means DUContext and TopDUContext.
 
176
 * */
 
177
template<class BaseContext>
 
178
class CppDUContext : public BaseContext {
 
179
  public:
 
180
    template<class Data>
 
181
    CppDUContext(Data& data) : BaseContext(data), m_instantiatedFrom(0) {
 
182
    }
 
183
 
 
184
    ///Parameters will be reached to the base-class
 
185
    template<class Param1, class Param2>
 
186
    CppDUContext( const Param1& p1, const Param2& p2, bool isInstantiationContext ) : BaseContext(p1, p2, isInstantiationContext), m_instantiatedFrom(0) {
 
187
      static_cast<DUChainBase*>(this)->d_func_dynamic()->setClassId(this);
 
188
    }
 
189
 
 
190
    ///Both parameters will be reached to the base-class. This fits TopDUContext.
 
191
    template<class Param1, class Param2, class Param3>
 
192
    CppDUContext( const Param1& p1, const Param2& p2, const Param3& p3) : BaseContext(p1, p2, p3), m_instantiatedFrom(0) {
 
193
      static_cast<DUChainBase*>(this)->d_func_dynamic()->setClassId(this);
 
194
    }
 
195
    template<class Param1, class Param2>
 
196
    CppDUContext( const Param1& p1, const Param2& p2) : BaseContext(p1, p2), m_instantiatedFrom(0) {
 
197
      static_cast<DUChainBase*>(this)->d_func_dynamic()->setClassId(this);
 
198
    }
 
199
    
 
200
    ///Matches the qualified identifier represented by the search item to the tail of the contexts scope identfier
 
201
    ///Also matches searches without template-parameters to fully instantiated contexts
 
202
    ///Returns true if they match
 
203
    inline bool matchSearchItem(DUContext::SearchItem::Ptr item, const DUContext* ctx) const {
 
204
        DUContext::SearchItem::PtrList items;
 
205
        while(1) {
 
206
          items << item;
 
207
          if(!item->next.isEmpty())
 
208
            item = item->next[0];
 
209
          else
 
210
            break;
 
211
        }
 
212
        
 
213
        while(ctx && !items.isEmpty()) {
 
214
          QualifiedIdentifier localId = ctx->localScopeIdentifier();
 
215
          
 
216
          if(localId.isEmpty())
 
217
            return false;
 
218
        
 
219
          int matchPos = localId.count()-1;
 
220
          while(!items.isEmpty() && matchPos >= 0) {
 
221
            
 
222
            if(items.back()->identifier.templateIdentifiersCount())
 
223
              return false; //Don't match when there is template parameters, as that needs other mechanisms
 
224
            
 
225
            if((!items.back()->identifier.templateIdentifiersCount() && items.back()->identifier.identifier() == localId.at(matchPos).identifier()) ||
 
226
                items.back()->identifier == localId.at(matchPos)) {
 
227
              --matchPos;
 
228
              items.resize(items.size()-1);
 
229
            }else{
 
230
              return false;
 
231
            }
 
232
          }
 
233
          
 
234
          if(items.isEmpty())
 
235
            return true;
 
236
          
 
237
          ctx = ctx->parentContext();
 
238
        }
 
239
        
 
240
        return false;
 
241
    }
 
242
 
 
243
    ///Overridden to take care of templates and other c++ specific things
 
244
    virtual bool findDeclarationsInternal(const DUContext::SearchItem::PtrList& identifiers, const SimpleCursor& position, const AbstractType::Ptr& dataType, DUContext::DeclarationList& ret, const TopDUContext* source, typename BaseContext::SearchFlags basicFlags, uint depth ) const
 
245
    {
 
246
      if(this->type() == DUContext::Class && identifiers.count() == 1 &&
 
247
        !(basicFlags & DUContext::NoSelfLookUp) && !(basicFlags & DUContext::OnlyFunctions) && this->localScopeIdentifier().count() &&
 
248
        !identifiers[0]->isExplicitlyGlobal) {
 
249
 
 
250
        //Check whether we're searching for just the name of this context's class. If yes, return this context's owner.
 
251
        if(matchSearchItem(identifiers[0], this)) {
 
252
          
 
253
          Declaration* owner = this->owner();
 
254
          if(owner) {
 
255
            if(basicFlags & DUContext::NoUndefinedTemplateParams) {
 
256
              //If no undefined template parameters are allowed, make sure this template has all parameters assigned.
 
257
              TemplateDeclaration* templateOwner = dynamic_cast<TemplateDeclaration*>(this->owner());
 
258
              if(templateOwner) {
 
259
                if(!templateOwner->instantiatedFrom())
 
260
                  return false;
 
261
                DUContext* templateContext = templateOwner->templateContext(source);
 
262
                if(templateContext) {
 
263
                  foreach(Declaration* decl, templateContext->localDeclarations()) {
 
264
                    if(decl->type<CppTemplateParameterType>()) {
 
265
                      return false;
 
266
                    }
 
267
                  }
 
268
                }
 
269
              }
 
270
            }
 
271
            
 
272
            ret << this->owner();
 
273
            return true;
 
274
          }
 
275
        }
 
276
      }
 
277
      
 
278
      if( basicFlags & BaseContext::DirectQualifiedLookup ) {
 
279
        //ifDebug( kDebug(9007) << "redirecting findDeclarationsInternal in " << this << "(" << this->scopeIdentifier() <<") for \"" << identifier.toString() << "\""; )
 
280
        //We use DirectQualifiedLookup to signalize that we don't need to do the whole scope-search, template-resolution etc. logic.
 
281
        return BaseContext::findDeclarationsInternal(identifiers, position, dataType, ret, source, basicFlags, depth );
 
282
      }
 
283
      
 
284
      FOREACH_ARRAY( const DUContext::SearchItem::Ptr& item, identifiers )
 
285
        foreach( const QualifiedIdentifier& id, item->toList() )
 
286
          if(!findDeclarationsInternal(id, position, dataType, ret, source, basicFlags))
 
287
            return false;
 
288
 
 
289
      // Remove all forward-declarations if there is a real declaration in the list
 
290
 
 
291
      bool haveForwardDeclaration = false;
 
292
      bool haveNonForwardDeclaration = false;
 
293
      
 
294
      for(int a = 0; a < ret.size(); ++a) {
 
295
        if(ret[a]->isForwardDeclaration())
 
296
          haveForwardDeclaration = true;
 
297
        else
 
298
          haveNonForwardDeclaration = true;
 
299
      }
 
300
 
 
301
      if(haveForwardDeclaration && haveNonForwardDeclaration) {
 
302
        DUContext::DeclarationList oldRet = ret;
 
303
        ret.clear();
 
304
        for(int a = 0; a < oldRet.size(); ++a)
 
305
          if(!oldRet[a]->isForwardDeclaration())
 
306
            ret.append(oldRet[a]);
 
307
      }
 
308
      return true;
 
309
    }
 
310
 
 
311
    bool findDeclarationsInternal(const QualifiedIdentifier& identifier, const SimpleCursor& position, const AbstractType::Ptr& dataType, DUContext::DeclarationList& ret, const TopDUContext* source, typename BaseContext::SearchFlags basicFlags) const
 
312
    {
 
313
      ifDebug( kDebug(9007) << "findDeclarationsInternal in " << this << "(" << this->scopeIdentifier() <<") for \"" << identifier.toString() << "\""; )
 
314
 
 
315
      FindDeclaration find( this, source, basicFlags, position, dataType );
 
316
 
 
317
      find.openQualifiedIdentifier( identifier.explicitlyGlobal() );
 
318
 
 
319
      int idCount = identifier.count();
 
320
      for( int num = 0; num < idCount; num++ )
 
321
      {
 
322
        {
 
323
          Identifier current = identifier.at(num);
 
324
          current.clearTemplateIdentifiers();
 
325
          find.openIdentifier(current);
 
326
        }
 
327
        
 
328
        {
 
329
          Identifier currentIdentifier = identifier.at(num);
 
330
 
 
331
          ///Step 1: Resolve the template-arguments
 
332
          //Since there may be non-type template-parameters, represent them as ExpressionEvaluationResult's
 
333
 
 
334
          int tempCount = currentIdentifier.templateIdentifiersCount();
 
335
          for( int a = 0; a < tempCount; a++ ) {
 
336
            //Use the already available mechanism for resolving delayed types
 
337
            Cpp::ExpressionEvaluationResult res;
 
338
            IndexedTypeIdentifier i = currentIdentifier.templateIdentifier(a);
 
339
            //If the identifier is empty, it is probably just a mark that a template should be instantiated, but without explicit paremeters.
 
340
            QualifiedIdentifier qid(i.identifier().identifier());
 
341
            if( !qid.isEmpty() ) {
 
342
              DelayedType::Ptr delayed( new DelayedType() );
 
343
              delayed->setIdentifier( i );
 
344
              
 
345
              res.type = Cpp::resolveDelayedTypes( delayed.cast<AbstractType>(), this, source, basicFlags & KDevelop::DUContext::NoUndefinedTemplateParams ? DUContext::NoUndefinedTemplateParams : DUContext::NoSearchFlags )->indexed();
 
346
              
 
347
              if( basicFlags & KDevelop::DUContext::NoUndefinedTemplateParams) {
 
348
                AbstractType::Ptr targetTypePtr = TypeUtils::unAliasedType(TypeUtils::targetType(res.type.abstractType(), 0));
 
349
                if (targetTypePtr.cast<CppTemplateParameterType>() || targetTypePtr.cast<DelayedType>()) {
 
350
                  return false;
 
351
                }
 
352
              }
 
353
 
 
354
              ifDebug( if( !res.isValid() ) kDebug(9007) << "Could not resolve template-parameter \"" << currentIdentifier.templateIdentifier(a).toString() << "\" in \"" << identifier.toString() << "resolved:" << res.toString(); )
 
355
            }
 
356
          
 
357
            find.openQualifiedIdentifier( res );
 
358
            find.closeQualifiedIdentifier();
 
359
          }
 
360
        }
 
361
 
 
362
        if( !find.closeIdentifier( num == idCount-1 ) )
 
363
          return false;
 
364
      }
 
365
      find.closeQualifiedIdentifier();
 
366
      
 
367
      foreach( const DeclarationPointer& decl, find.lastDeclarations() )
 
368
        ret.append(decl.data());
 
369
      
 
370
      return true;
 
371
    }
 
372
 
 
373
    virtual void findLocalDeclarationsInternal( const Identifier& identifier, const SimpleCursor & position, const AbstractType::Ptr& dataType, DUContext::DeclarationList& ret, const TopDUContext* source, typename BaseContext::SearchFlags flags ) const
 
374
    {
 
375
      ifDebug( kDebug(9007) << "findLocalDeclarationsInternal in " << this << "with parent" << this->parentContext() << "(" << this->scopeIdentifier() <<") for \"" << identifier.toString() << "\""; )
 
376
      ifDebug( if( BaseContext::owner() && BaseContext::owner() ) kDebug(9007) << "in declaration: " << "(" << BaseContext::owner()->toString(); )
 
377
      /**
 
378
        - When searching local declarations:
 
379
         - Check whether they are already in the instantiated context, if yes return them
 
380
         - If not, Search in non-instantiated context(only for local declarations), then:
 
381
           - Copy & Change returned objects:
 
382
             - Resolve virtual types (DelayedType)
 
383
             - Change parent-context to virtual context
 
384
             - Change internal context, (create virtual, move set parent)
 
385
      * */
 
386
 
 
387
        int retCount = ret.size();
 
388
      
 
389
        BaseContext::findLocalDeclarationsInternal(identifier, position, dataType, ret, source, flags );
 
390
 
 
391
        ifDebug( kDebug(9007) << "basically found:" << ret.count() - retCount << "containing" << BaseContext::localDeclarations().count() << "searching-position" << position.textCursor(); )
 
392
 
 
393
        if( !(flags & DUContext::NoFiltering) ) {
 
394
          //Filter out constructors and if needed unresolved template-params
 
395
          for(int a = 0; a < ret.size(); ) {
 
396
            
 
397
            AbstractType::Ptr retAbstractTypePtr = ret[a]->abstractType();
 
398
            if( ( (flags & KDevelop::DUContext::NoUndefinedTemplateParams) && retAbstractTypePtr.cast<CppTemplateParameterType>() )
 
399
                || ( (!(flags & BaseContext::OnlyFunctions)) &&  (dynamic_cast<ClassFunctionDeclaration*>(ret[a]) && static_cast<ClassFunctionDeclaration*>(ret[a])->isConstructor() ) ) ) { //Maybe this filtering should be done in the du-chain?
 
400
                
 
401
              //Erase the item
 
402
              for(int b = a+1; b < ret.size(); ++b)
 
403
                ret[b-1] = ret[b];
 
404
              ret.resize(ret.size()-1);
 
405
              //kDebug(9007) << "filtered out 1 declaration";
 
406
            } else {
 
407
              ++a;
 
408
            }
 
409
          }
 
410
        }
 
411
 
 
412
        ifDebug( if( BaseContext::owner() && BaseContext::owner() ) kDebug(9007) << "in declaration: " << "(" << BaseContext::owner()->toString(); )
 
413
        ifDebug( kDebug(9007) << "instantiated from:" << m_instantiatedFrom; )
 
414
        
 
415
        if( m_instantiatedFrom && ret.size() == retCount ) {
 
416
          ///Search in the context this one was instantiated from
 
417
          DUContext::DeclarationList decls;
 
418
          ifDebug( kDebug(9007) << "searching base"; )
 
419
          m_instantiatedFrom->findLocalDeclarationsInternal( identifier, position, dataType, decls, source, flags );
 
420
          
 
421
          ifDebug( if( BaseContext::owner() && BaseContext::owner() ) kDebug(9007) << "in declaration: " << "(" << BaseContext::owner()->toString(); )
 
422
          ifDebug( kDebug(9007) << "found" << decls.count() << "in base"; )
 
423
          
 
424
          InstantiationInformation memberInstantiationInformation;
 
425
          memberInstantiationInformation.previousInstantiationInformation = m_instantiatedWith;
 
426
          
 
427
          FOREACH_ARRAY( Declaration* decl, decls ) {
 
428
            TemplateDeclaration* templateDecl = dynamic_cast<TemplateDeclaration*>(decl);
 
429
            if(!templateDecl) {
 
430
              kDebug() << "problem";
 
431
            } else {
 
432
              Declaration* copy;
 
433
              
 
434
              DUContext* current = decl->context();
 
435
              while(current != m_instantiatedFrom && current)
 
436
              {
 
437
                // The declaration has been propagated up from a sub-context like an enumerator, add more empty instantiation information
 
438
                // so the depth is matched correctly by the information
 
439
                InstantiationInformation i;
 
440
                i.previousInstantiationInformation = memberInstantiationInformation.indexed();
 
441
                memberInstantiationInformation = i;
 
442
                current = current->parentContext();
 
443
              }
 
444
              Q_ASSERT(source);
 
445
              copy = templateDecl->instantiate(memberInstantiationInformation, source);
 
446
              //This can happen in case of explicit specializations
 
447
//               if(copy->context() != this)
 
448
//                 kWarning() << "serious problem: Instatiation is in wrong context, should be in this one";
 
449
 
 
450
              if(copy)
 
451
                ret.append(copy);
 
452
            }
 
453
          }
 
454
        }
 
455
    }
 
456
    
 
457
    virtual void deleteUses() {
 
458
      QMutexLocker l(&cppDuContextInstantiationsMutex);
 
459
      foreach(CppDUContext<BaseContext>* ctx, m_instatiations)
 
460
        ctx->deleteUses();
 
461
      BaseContext::deleteUses();
 
462
    }
 
463
    
 
464
    virtual bool foundEnough( const DUContext::DeclarationList& decls, DUContext::SearchFlags flags ) const
 
465
    {
 
466
      if(flags & DUContext::NoFiltering)
 
467
        return false;
 
468
      
 
469
      if( decls.isEmpty() )
 
470
        return false;
 
471
 
 
472
      if( dynamic_cast<const KDevelop::AbstractFunctionDeclaration*>(decls[0]) && BaseContext::type() != DUContext::Class ) //In classes, one function hides all overloads
 
473
        return false; //Collect overloaded function-declarations
 
474
 
 
475
      return true;
 
476
    }
 
477
 
 
478
    /**
 
479
     * Set the context which this is instantiated from. This context will be strictly attached to that context, and will be deleted once the other is deleted.
 
480
     * */
 
481
    void setInstantiatedFrom( CppDUContext<BaseContext>* context, const InstantiationInformation& templateArguments )
 
482
    {
 
483
      Q_ASSERT(!dynamic_cast<TopDUContext*>(this));
 
484
      if(context && context->m_instantiatedFrom) {
 
485
        setInstantiatedFrom(context->m_instantiatedFrom, templateArguments);
 
486
        return;
 
487
      }
 
488
      QMutexLocker l(&cppDuContextInstantiationsMutex);
 
489
      
 
490
      if( m_instantiatedFrom ) {
 
491
        Q_ASSERT(m_instantiatedFrom->m_instatiations[m_instantiatedWith] == this);
 
492
        m_instantiatedFrom->m_instatiations.remove( m_instantiatedWith );
 
493
      }
 
494
      
 
495
      m_instantiatedWith = templateArguments.indexed();
 
496
      if(context) {
 
497
        //Change the identifier so it contains the template-parameters
 
498
        QualifiedIdentifier totalId = this->localScopeIdentifier();
 
499
        KDevelop::Identifier id;
 
500
        if( !totalId.isEmpty() ) {
 
501
          id = totalId.last();
 
502
          totalId.pop();
 
503
        }
 
504
        
 
505
        id.clearTemplateIdentifiers();
 
506
        FOREACH_FUNCTION(const IndexedType& arg, templateArguments.templateParameters) {
 
507
          AbstractType::Ptr type(arg.abstractType());
 
508
          IdentifiedType* identified = dynamic_cast<IdentifiedType*>(type.unsafeData());
 
509
          if(identified)
 
510
            id.appendTemplateIdentifier( IndexedTypeIdentifier(identified->qualifiedIdentifier()) );
 
511
          else if(type)
 
512
            id.appendTemplateIdentifier( IndexedTypeIdentifier(type->toString(), true) );
 
513
          else
 
514
            id.appendTemplateIdentifier( IndexedTypeIdentifier("no type") );
 
515
        }
 
516
 
 
517
        totalId.push(id);
 
518
        
 
519
        this->setLocalScopeIdentifier(totalId);
 
520
      }
 
521
      
 
522
      m_instantiatedFrom = context;
 
523
      Q_ASSERT(m_instantiatedFrom != this);
 
524
      if(m_instantiatedFrom) {
 
525
        if(!m_instantiatedFrom->m_instatiations.contains(m_instantiatedWith)) {
 
526
          m_instantiatedFrom->m_instatiations.insert( m_instantiatedWith, this );
 
527
        }else{
 
528
          kDebug(9007) << "created orphaned instantiation for" << context->m_instatiations[m_instantiatedWith]->scopeIdentifier(true).toString();
 
529
          m_instantiatedFrom = 0;
 
530
        }
 
531
      }
 
532
    }
 
533
    
 
534
    virtual void applyUpwardsAliases(DUContext::SearchItem::PtrList& identifiers, const TopDUContext* source) const
 
535
    {
 
536
      BaseContext::applyUpwardsAliases(identifiers, source);
 
537
      ///@see Iso C++ 3.4.1 : Unqualified name lookup: 
 
538
      ///We need to make sure that when leaving a function definition, the namespace components are searched
 
539
      DUContext::ContextType type = BaseContext::type();
 
540
      
 
541
      if(type == DUContext::Function || type == DUContext::Other || type == DUContext::Helper)
 
542
      {
 
543
        QualifiedIdentifier prefix = BaseContext::localScopeIdentifier();
 
544
        if(prefix.count() > 1) {
 
545
          prefix = Cpp::namespaceScopeComponentFromContext(prefix, this, source);
 
546
          
 
547
          if(!prefix.isEmpty()) {
 
548
            prefix.setExplicitlyGlobal(true);
 
549
            
 
550
            DUContext::SearchItem::Ptr newItem(new DUContext::SearchItem(prefix));
 
551
            newItem->addToEachNode(identifiers);
 
552
            
 
553
            if(!newItem->next.isEmpty()) //Can happen if the identifier was explicitly global
 
554
              identifiers.insert(0, newItem);
 
555
          }
 
556
        }
 
557
      }
 
558
    }
 
559
 
 
560
    /**
 
561
     * If this returns nonzero value, this context is a instatiation of some other context, and that other context will be returned here.
 
562
     * */
 
563
    CppDUContext<BaseContext>* instantiatedFrom() const {
 
564
      return m_instantiatedFrom;
 
565
    }
 
566
 
 
567
    virtual bool inDUChain() const {
 
568
      ///There must be no changes from the moment m_instantiatedFrom is set, because then it can be found as an instantiation by other threads
 
569
      return m_instantiatedFrom || BaseContext::inDUChain();
 
570
    }
 
571
    
 
572
    IndexedInstantiationInformation instantiatedWith() const {
 
573
      return m_instantiatedWith;
 
574
    }
 
575
    
 
576
    virtual bool shouldSearchInParent(typename BaseContext::SearchFlags flags) const {
 
577
      //If the parent context is a class context, we should even search it from an import
 
578
      return (BaseContext::parentContext() && BaseContext::parentContext()->type() == DUContext::Class) || BaseContext::shouldSearchInParent(flags);
 
579
    }
 
580
 
 
581
    virtual DUContext* specialize(IndexedInstantiationInformation specialization, const TopDUContext* topContext, int upDistance) {
 
582
      if(specialization.index() == 0)
 
583
        return this;
 
584
      else {
 
585
        InstantiationInformation information = specialization.information();
 
586
        
 
587
        //Add empty elements until the specified depth
 
588
        for(int a = 0; a < upDistance; ++a) {
 
589
          InstantiationInformation nextInformation;
 
590
          nextInformation.previousInstantiationInformation = information.indexed();
 
591
          information = nextInformation;
 
592
        }
 
593
        
 
594
        return instantiate(information, topContext);
 
595
      }
 
596
    }
 
597
 
 
598
    ///@see TemplateDeclaration::instantiate
 
599
    DUContext* instantiate(InstantiationInformation info, const TopDUContext* source) {
 
600
      if(!info.isValid() || m_instantiatedWith == info.indexed() || !this->parentContext())
 
601
        return this;
 
602
 
 
603
      if(m_instantiatedFrom)
 
604
        return m_instantiatedFrom->instantiate(info, source);
 
605
      
 
606
      {
 
607
        typename QHash<IndexedInstantiationInformation, CppDUContext<BaseContext>* >::const_iterator it = m_instatiations.constFind(info.indexed());
 
608
        if(it != m_instatiations.constEnd())
 
609
          return *it;
 
610
      }
 
611
      
 
612
      if(this->owner()) {
 
613
        TemplateDeclaration* templ = dynamic_cast<TemplateDeclaration*>(this->owner());
 
614
        if(templ) {
 
615
          Declaration* instantiatedDecl = templ->instantiate(info, source);
 
616
          if(!instantiatedDecl)
 
617
            return 0;
 
618
          return instantiatedDecl->internalContext();
 
619
        }
 
620
      }
 
621
      
 
622
      DUContext* surroundingContext = this->parentContext();
 
623
      Q_ASSERT(surroundingContext);
 
624
      {
 
625
        //This context does not have an attached declaration, but it needs to be instantiated.
 
626
        CppDUContext<DUContext>* parent = dynamic_cast<CppDUContext<DUContext>* >(this->parentContext());
 
627
        if(parent)
 
628
          surroundingContext = parent->instantiate(info.previousInstantiationInformation.information(), source);
 
629
      }
 
630
      
 
631
      if(!surroundingContext)
 
632
        return 0;
 
633
      
 
634
      return instantiateDeclarationAndContext( surroundingContext, source, this, info, 0, 0 );
 
635
    }
 
636
    
 
637
    virtual QWidget* createNavigationWidget(Declaration* decl, TopDUContext* topContext, const QString& htmlPrefix, const QString& htmlSuffix) const;
 
638
    
 
639
    enum {
 
640
      Identity = BaseContext::Identity + 50
 
641
    };
 
642
    
 
643
    ///Duchain must be write-locked
 
644
    void deleteAllInstantiations() {
 
645
      //Specializations will be destroyed the same time this is destroyed
 
646
      CppDUContext<BaseContext>* oldFirst = 0;
 
647
      QMutexLocker l(&cppDuContextInstantiationsMutex);
 
648
      while(!m_instatiations.isEmpty()) {
 
649
        CppDUContext<BaseContext>* first = 0;
 
650
        first = *m_instatiations.begin();
 
651
        
 
652
        Q_ASSERT(first != oldFirst);
 
653
        
 
654
        l.unlock();
 
655
        
 
656
        if(first->isAnonymous()) {
 
657
          Q_ASSERT(first->m_instantiatedFrom == this);
 
658
          delete first;
 
659
        } else {
 
660
          Q_ASSERT(first->m_instantiatedFrom == this);
 
661
          first->setInstantiatedFrom(0, InstantiationInformation());
 
662
          Q_ASSERT(first->m_instantiatedFrom == 0);
 
663
        }
 
664
        
 
665
        oldFirst = first;
 
666
        
 
667
        l.relock();
 
668
      }      
 
669
    }
 
670
    
 
671
    //Overridden to instantiate all not yet instantiated local declarations
 
672
    virtual QVector<Declaration*> localDeclarations(const TopDUContext* source) const {
 
673
      
 
674
      if(m_instantiatedFrom && source && BaseContext::type() != DUContext::Template) {
 
675
        QVector<Declaration*> decls = m_instantiatedFrom->localDeclarations(source);
 
676
//         DUContext::DeclarationList temp;
 
677
 
 
678
        InstantiationInformation inf;
 
679
        inf.previousInstantiationInformation = m_instantiatedWith;
 
680
 
 
681
        foreach( Declaration* baseDecl, decls ) {
 
682
          TemplateDeclaration* tempDecl = dynamic_cast<TemplateDeclaration*>(baseDecl);
 
683
          if(tempDecl) {
 
684
            tempDecl->instantiate(inf, source);
 
685
          }else{
 
686
            kDebug() << "Strange: non-template within template context";
 
687
            KDevVarLengthArray<Declaration*, 40> temp;
 
688
            this->findLocalDeclarationsInternal( baseDecl->identifier(), SimpleCursor::invalid(), AbstractType::Ptr(), temp, source, DUContext::NoFiltering );
 
689
          }
 
690
        }
 
691
      }
 
692
        
 
693
        return BaseContext::localDeclarations(source);
 
694
    }
 
695
    
 
696
  private:
 
697
    ~CppDUContext() {
 
698
 
 
699
      if(m_instantiatedFrom)
 
700
        setInstantiatedFrom(0, InstantiationInformation());
 
701
      
 
702
      deleteAllInstantiations();
 
703
    }
 
704
 
 
705
    virtual void mergeDeclarationsInternal(QList< QPair<Declaration*, int> >& definitions, const SimpleCursor& position, QHash<const DUContext*, bool>& hadContexts, const TopDUContext* source,  bool searchInParents, int currentDepth) const
 
706
    {
 
707
      Q_ASSERT(source);
 
708
//       kDebug() << "checking in" << this->scopeIdentifier(true).toString();
 
709
      if( m_instantiatedFrom )
 
710
      {
 
711
        //We need to make sure that all declarations from the specialization-base are instantiated, so they are returned.
 
712
 
 
713
        //This requests all declarations, so they all will be instantiated and instances of them added into this context.
 
714
        //DUContext::mergeDeclarationsInternal will then get them.
 
715
        
 
716
        //Calling localDeclarations() instantiates all not yet instantiated member declarations
 
717
        localDeclarations(source);
 
718
        
 
719
//         kDebug() << "final count of local declarations:" << this->localDeclarations().count();
 
720
        
 
721
        //Instantiate up-propagating child-contexts with the correct same instantiation-information
 
722
        //This for examples makes unnamed enums accessible
 
723
        InstantiationInformation inf;
 
724
        inf.previousInstantiationInformation = m_instantiatedWith;
 
725
        
 
726
        foreach(DUContext* child, m_instantiatedFrom->childContexts()) {
 
727
//           kDebug() << "checking child-context" << child->isPropagateDeclarations();
 
728
          
 
729
          if(child->isPropagateDeclarations())
 
730
            static_cast<CppDUContext<BaseContext>*>(static_cast<CppDUContext<BaseContext>*>(child)->instantiate(inf, source))->mergeDeclarationsInternal(definitions, position, hadContexts, source, searchInParents, currentDepth);
 
731
        }
 
732
      }
 
733
 
 
734
      BaseContext::mergeDeclarationsInternal(definitions, position, hadContexts, source, searchInParents, currentDepth);
 
735
    }
 
736
 
 
737
    CppDUContext<BaseContext>* m_instantiatedFrom;
 
738
 
 
739
    ///Every access to m_instatiations must be serialized through instatiationsMutex, because they may be written without a write-lock
 
740
    QHash<IndexedInstantiationInformation, CppDUContext<BaseContext>* > m_instatiations;
 
741
    IndexedInstantiationInformation m_instantiatedWith;
 
742
};
 
743
 
 
744
///Returns whether the given declaration depends on a missing template-parameter
 
745
bool isTemplateDependent(Declaration* decl);
 
746
bool isTemplateDependent(DUContext* context);
 
747
 
 
748
}
 
749
 
 
750
#endif