1
/* This file is part of KDevelop
2
Copyright 2006 Roberto Raggi <roberto@kdevelop.org>
3
Copyright 2006-2008 Hamish Rodda <rodda@kde.org>
4
Copyright 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de>
6
This library is free software; you can redistribute it and/or
7
modify it under the terms of the GNU Library General Public
8
License version 2 as published by the Free Software Foundation.
10
This library is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Library General Public License for more details.
15
You should have received a copy of the GNU Library General Public License
16
along with this library; see the file COPYING.LIB. If not, write to
17
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18
Boston, MA 02110-1301, USA.
21
#include "contextbuilder.h"
24
#include <ktexteditor/smartrange.h>
25
#include <ktexteditor/smartinterface.h>
26
#include <ktexteditor/document.h>
28
#include <language/duchain/duchain.h>
29
#include <language/duchain/topducontext.h>
30
#include <language/duchain/declaration.h>
31
#include <language/duchain/use.h>
32
#include <language/duchain/smartconverter.h>
33
#include <util/pushvalue.h>
35
#include "parsesession.h"
36
#include "name_compiler.h"
37
#include <language/duchain/dumpchain.h>
38
#include "environmentmanager.h"
41
#include "cppdebughelper.h"
42
#include "debugbuilders.h"
43
#include "rpp/chartools.h"
45
#include <klocalizedstring.h>
47
using namespace KTextEditor;
48
using namespace KDevelop;
51
bool containsContext( const QList<LineContextPair>& lineContexts, TopDUContext* context ) {
52
foreach( const LineContextPair& ctx, lineContexts )
53
if( ctx.context.data() == context )
58
bool importsContext( const QList<LineContextPair>& lineContexts, TopDUContext* context ) {
59
foreach( const LineContextPair& ctx, lineContexts )
60
if( ctx.context && ctx.context->imports(context, KDevelop::SimpleCursor()) )
65
void removeContext( QList<LineContextPair>& lineContexts, TopDUContext* context ) {
66
for( QList<LineContextPair>::iterator it = lineContexts.begin(); it != lineContexts.end(); ++it )
67
if( (*it).context.data() == context ) {
68
lineContexts.erase(it);
73
///Retrieves the first and last item from a list
75
void getFirstLast(AST** first, AST** last, const ListNode<_Tp> *nodes)
84
*it = nodes->toFront(),
100
ContextBuilder::ContextBuilder ()
102
, m_inFunctionDefinition(false)
103
, m_templateDeclarationDepth(0)
104
, m_typeSpecifierWithoutInitDeclarators((uint)-1)
105
, m_onlyComputeVisible(false)
106
, m_onlyComputeSimplified(false)
107
, m_computeEmpty(false)
108
, m_currentInitializer(0)
113
ContextBuilder::ContextBuilder (ParseSession* session)
115
, m_inFunctionDefinition(false)
116
, m_templateDeclarationDepth(0)
117
, m_typeSpecifierWithoutInitDeclarators((uint)-1)
118
, m_onlyComputeVisible(false)
119
, m_onlyComputeSimplified(false)
120
, m_computeEmpty(false)
121
, m_currentInitializer(0)
124
setEditor(new CppEditorIntegrator(session), true);
127
ContextBuilder::ContextBuilder (CppEditorIntegrator* editor)
129
, m_inFunctionDefinition(false)
130
, m_templateDeclarationDepth(0)
131
, m_typeSpecifierWithoutInitDeclarators((uint)-1)
132
, m_onlyComputeVisible(false)
133
, m_onlyComputeSimplified(false)
134
, m_computeEmpty(false)
135
, m_currentInitializer(0)
138
setEditor(editor, false);
141
void ContextBuilder::setOnlyComputeVisible(bool onlyVisible) {
142
m_onlyComputeVisible = onlyVisible;
145
void ContextBuilder::setComputeSimplified(bool simplified)
147
m_onlyComputeSimplified = simplified;
150
void ContextBuilder::setComputeEmpty(bool empty)
152
m_computeEmpty = empty;
156
void ContextBuilder::createUserProblem(AST* node, QString text) {
157
DUChainWriteLocker lock(DUChain::lock());
158
KDevelop::ProblemPointer problem(new KDevelop::Problem);
159
problem->setDescription(text);
160
problem->setSource(KDevelop::ProblemData::DUChainBuilder);
161
problem->setFinalLocation(DocumentRange(HashedString(currentContext()->url().str()), editor()->findRange(node).textRange()));
162
currentContext()->topContext()->addProblem(problem);
165
void ContextBuilder::addBaseType( KDevelop::BaseClassInstance base, BaseSpecifierAST *node ) {
166
DUChainWriteLocker lock(DUChain::lock());
168
addImportedContexts(); //Make sure the template-contexts are imported first, before any parent-class contexts.
170
Q_ASSERT(currentContext()->type() == DUContext::Class);
171
AbstractType::Ptr baseClass = base.baseClass.abstractType();
172
IdentifiedType* idType = dynamic_cast<IdentifiedType*>(baseClass.unsafeData());
173
Declaration* idDecl = 0;
174
if( idType && (idDecl = idType->declaration(currentContext()->topContext())) ) {
175
DUContext* ctx = idDecl->logicalInternalContext(currentContext()->topContext());
177
currentContext()->addImportedParentContext( ctx );
179
currentContext()->addIndirectImport( DUContext::Import(idType->declarationId()) );
180
QString text = i18n("Could not resolve base class, adding it indirectly: %1", (base.baseClass ? base.baseClass.abstractType()->toString() : QString()));
182
createUserProblem(node, text);
184
} else if( !baseClass.cast<DelayedType>() ) {
185
QString text = i18n("Invalid base class: %1", (base.baseClass ? base.baseClass.abstractType()->toString() : QString()));
187
createUserProblem(node, text);
191
void ContextBuilder::setEditor(CppEditorIntegrator* editor, bool ownsEditorIntegrator)
193
ContextBuilderBase::setEditor(editor, ownsEditorIntegrator);
194
m_nameCompiler = new NameCompiler(editor->parseSession());
198
void addImportedParentContextSafely(DUContext* context, DUContext* import) {
199
if(import->imports(context)) {
200
kDebug() << "prevented endless recursive import";
202
context->addImportedParentContext(import);
206
QualifiedIdentifier ContextBuilder::identifierForNode(NameAST* id) {
207
QualifiedIdentifier ret;
208
identifierForNode(id, ret);
212
void ContextBuilder::setMapAst(bool mapAst)
217
void ContextBuilder::identifierForNode(NameAST* id, QualifiedIdentifier& target)
219
return identifierForNode(id, 0, target);
222
void ContextBuilder::startVisiting( AST* node )
227
void ContextBuilder::setContextOnNode( AST* node, DUContext* ctx )
229
node->ducontext = ctx;
232
DUContext* ContextBuilder::contextFromNode( AST* node )
234
return node->ducontext;
237
KTextEditor::Range ContextBuilder::editorFindRange( AST* fromRange, AST* toRange )
239
return editor()->findRange(fromRange, toRange).textRange();
242
KTextEditor::Range ContextBuilder::editorFindRangeForContext( AST* fromRange, AST* toRange )
244
return editor()->findRangeForContext(fromRange->start_token, toRange->end_token).textRange();
247
ContextBuilder::~ContextBuilder ()
249
delete m_nameCompiler;
252
QPair<DUContext*, QualifiedIdentifier> ContextBuilder::findPrefixContext(const QualifiedIdentifier& id, KDevelop::SimpleCursor pos) {
254
return qMakePair((DUContext*)0, QualifiedIdentifier());
256
QualifiedIdentifier prefixId(id);
259
DUContext* import = 0;
262
DUChainReadLocker lock(DUChain::lock());
264
QualifiedIdentifier currentScopeId = currentContext()->scopeIdentifier(true);
266
QList<Declaration*> decls = currentContext()->findDeclarations(prefixId, pos);
268
if(!decls.isEmpty()) {
269
DUContext* classContext = decls.first()->logicalInternalContext(0);
270
if(classContext && classContext->type() == DUContext::Class) {
271
import = classContext;
272
//Change the prefix-id so it respects namespace-imports
274
prefixId = classContext->scopeIdentifier(true);
275
if(prefixId.count() >= currentScopeId.count() && prefixId.left(currentScopeId.count()) == currentScopeId)
276
prefixId = prefixId.mid(currentScopeId.count());
278
kDebug() << "resolved bad prefix context. Should start with" << currentScopeId.toString() << "but is" << prefixId.toString();
283
return qMakePair(import, prefixId);
286
void ContextBuilder::openPrefixContext(AST* ast, const QualifiedIdentifier& id, const SimpleCursor& pos) {
290
//When creating a prefix-context that is there to embed a class within another class, import the enclosing class into that context.
291
//That way items from the base class can be found.
293
QPair<DUContext*, QualifiedIdentifier> prefix = findPrefixContext(id, pos);
295
openContext(ast, DUContext::Helper, prefix.second);
297
DUContext* import = prefix.first;
300
DUChainWriteLocker lock(DUChain::lock());
301
addImportedParentContextSafely(currentContext(), import);
305
void ContextBuilder::closePrefixContext(const QualifiedIdentifier& id) {
311
void ContextBuilder::visitTemplateDeclaration(TemplateDeclarationAST * ast) {
313
++m_templateDeclarationDepth;
315
if(!m_onlyComputeSimplified)
318
getFirstLast(&first, &last, ast->template_parameters);
322
ctx = openContext(first, last, DUContext::Template); //Open anonymous context for the template-parameters
324
ctx = openContextEmpty(ast, DUContext::Template); //Open an empty context, because there are no template-parameters
326
visitNodes(this,ast->template_parameters);
329
queueImportedContext(ctx); //Import the context into the following function-argument context(so the template-parameters can be found from there)
332
DefaultVisitor::visit(ast->declaration);
334
--m_templateDeclarationDepth;
337
KDevelop::TopDUContext* ContextBuilder::buildProxyContextFromContent(Cpp::EnvironmentFilePointer file, const TopDUContextPointer& content, const TopDUContextPointer& updateContext)
339
Cpp::EnvironmentFile* filePtr = const_cast<Cpp::EnvironmentFile*>(file.data() );
341
filePtr->setIsProxyContext(true);
343
//Never give smart-ranges to proxy-contexts
344
editor()->setCurrentUrl(file->url(), false);
346
TopDUContext* topLevelContext = 0;
348
DUChainWriteLocker lock(DUChain::lock());
349
topLevelContext = updateContext.data();
351
CppDUContext<TopDUContext>* cppContext = 0;
353
if (topLevelContext) {
354
kDebug(9007) << "ContextBuilder::buildProxyContextFromContent: recompiling";
356
Q_ASSERT(dynamic_cast<CppDUContext<TopDUContext>* >(topLevelContext));
357
cppContext = static_cast<CppDUContext<TopDUContext>* >(topLevelContext);
359
DUChain::self()->updateContextEnvironment( topLevelContext, filePtr );
361
kDebug(9007) << "ContextBuilder::buildProxyContextFromContent: compiling";
363
topLevelContext = new CppDUContext<TopDUContext>(editor()->currentUrl(), SimpleRange(), filePtr);
364
topLevelContext->setType(DUContext::Global);
366
Q_ASSERT(dynamic_cast<CppDUContext<TopDUContext>* >(topLevelContext));
367
cppContext = static_cast<CppDUContext<TopDUContext>* >(topLevelContext);
369
DUChain::self()->addDocumentChain(topLevelContext);
371
topLevelContext->updateImportsCache(); //Mark that we will use a cached import-structure
375
cppContext->clearImportedParentContexts();
376
cppContext->addImportedParentContext(content.data());
377
cppContext->updateImportsCache(); //Mark that we will use a cached import-structure
379
///This happens if a content-context is deleted from the du-chain during the time that the du-chain is not locked by this thread
380
kDebug(9007) << "ContextBuilder::buildProxyContextFromContent: Content-context lost for " << file->url().str();
383
Q_ASSERT(topLevelContext->importedParentContexts().count());
386
return topLevelContext;
389
ReferencedTopDUContext ContextBuilder::buildContexts(Cpp::EnvironmentFilePointer file, AST *node, IncludeFileList* includes, const ReferencedTopDUContext& updateContext, bool removeOldImports)
392
setCompilingContexts(true);
395
DUChainWriteLocker lock(DUChain::lock());
396
if(updateContext && (updateContext->parsingEnvironmentFile() && updateContext->parsingEnvironmentFile()->isProxyContext())) {
397
kDebug(9007) << "updating a context " << file->url().str() << " from a proxy-context to a content-context";
398
updateContext->parsingEnvironmentFile()->setIsProxyContext(false);
402
if(editor()->currentUrl() != file->url())
403
editor()->setCurrentUrl(file->url(), true);
405
ReferencedTopDUContext topLevelContext;
407
DUChainWriteLocker lock(DUChain::lock());
408
topLevelContext = updateContext;
410
if( topLevelContext && topLevelContext->smartRange() && !(topLevelContext->parsingEnvironmentFile() && topLevelContext->parsingEnvironmentFile()->isProxyContext()))
411
if (topLevelContext->smartRange()->parentRange()) { //Top-range must have no parent, else something is wrong with the structure
412
kWarning() << *topLevelContext->smartRange() << "erroneously has a parent range" << *topLevelContext->smartRange()->parentRange();
416
if (topLevelContext) {
417
kDebug(9007) << "ContextBuilder::buildContexts: recompiling";
418
setRecompiling(true);
420
if (compilingContexts()) {
422
LockedSmartInterface iface = editor()->smart();
423
if (iface && topLevelContext->range().textRange() != iface.currentDocument()->documentRange()) {
424
topLevelContext->setRange(SimpleRange(iface.currentDocument()->documentRange()));
425
//This happens the whole file is deleted, and then a space inserted.
426
kDebug(9007) << "WARNING: Top-level context has wrong size: " << topLevelContext->range().textRange() << " should be: " << iface.currentDocument()->documentRange();
430
DUChain::self()->updateContextEnvironment( topLevelContext, const_cast<Cpp::EnvironmentFile*>(file.data() ) );
432
kDebug(9007) << "ContextBuilder::buildContexts: compiling";
433
setRecompiling(false);
435
Q_ASSERT(compilingContexts());
437
LockedSmartInterface iface = editor()->smart();
438
topLevelContext = new CppDUContext<TopDUContext>(editor()->currentUrl(), iface.currentDocument() ? SimpleRange(iface.currentDocument()->documentRange()) : SimpleRange(SimpleCursor(0,0), SimpleCursor(INT_MAX, INT_MAX)), const_cast<Cpp::EnvironmentFile*>(file.data()));
440
topLevelContext->setSmartRange(editor()->topRange(iface, CppEditorIntegrator::DefinitionUseChain), DocumentRangeObject::Own);
441
topLevelContext->setType(DUContext::Global);
442
topLevelContext->setFlags((TopDUContext::Flags)(TopDUContext::UpdatingContext | topLevelContext->flags()));
443
DUChain::self()->addDocumentChain(topLevelContext);
445
topLevelContext->updateImportsCache(); //Mark that we will use a cached import-structure
448
setEncountered(topLevelContext);
451
if(removeOldImports) {
452
foreach (const DUContext::Import &parent, topLevelContext->importedParentContexts())
453
if (!containsContext(*includes, dynamic_cast<TopDUContext*>(parent.context(0))))
454
topLevelContext->removeImportedParentContext(parent.context(0));
457
QList< QPair<TopDUContext*, SimpleCursor> > realIncluded;
458
QList< QPair<TopDUContext*, SimpleCursor> > realTemporaryIncluded;
459
foreach (const LineContextPair &included, *includes)
460
if(!included.temporary)
461
realIncluded << qMakePair(included.context.data(), SimpleCursor(included.sourceLine, 0));
463
realTemporaryIncluded << qMakePair(included.context.data(), SimpleCursor(included.sourceLine, 0));
465
topLevelContext->addImportedParentContexts(realIncluded);
466
topLevelContext->addImportedParentContexts(realTemporaryIncluded, true);
468
topLevelContext->updateImportsCache();
473
DUChainReadLocker lock(DUChain::lock());
474
//If we're debugging the current file, dump its preprocessed contents and the AST
475
ifDebugFile( HashedString(file->identity().url().str()), { kDebug() << stringFromContents(editor()->parseSession()->contentsVector()); Cpp::DumpChain dump; dump.dump(node, editor()->parseSession()); } );
480
//Empty the top-context, in case we're updating
481
DUChainWriteLocker lock(DUChain::lock());
482
topLevelContext->cleanIfNotEncountered(QSet<DUChainBase*>());
484
node->ducontext = topLevelContext;
489
LockedSmartInterface iface = editor()->smart();
490
if (iface && topLevelContext->range().textRange() != iface.currentDocument()->documentRange()) {
491
kDebug(9007) << "WARNING: Top-level context has wrong size: " << topLevelContext->range().textRange() << " should be: " << iface.currentDocument()->documentRange();
492
topLevelContext->setRange( SimpleRange(iface.currentDocument()->documentRange()) );
497
DUChainReadLocker lock(DUChain::lock());
499
kDebug(9007) << "built top-level context with" << topLevelContext->localDeclarations().size() << "declarations and" << topLevelContext->importedParentContexts().size() << "included files";
500
//If we're debugging the current file, dump the du-chain and the smart ranges
501
ifDebugFile( HashedString(file->identity().url().str()), { KDevelop::DumpChain dump; dump.dump(topLevelContext); if(topLevelContext->smartRange()) dump.dumpRanges(topLevelContext->smartRange()); } );
503
/* if( m_recompiling ) {
505
dump.dump(topLevelContext);
506
kDebug(9007) << dump.dotGraph(topLevelContext);
510
setCompilingContexts(false);
512
if (!m_importedParentContexts.isEmpty()) {
513
DUChainReadLocker lock(DUChain::lock());
514
kWarning() << file->url().str() << "Previous parameter declaration context didn't get used??" ;
515
// KDevelop::DumpChain dump;
516
// dump.dump(topLevelContext);
517
m_importedParentContexts.clear();
521
DUChainWriteLocker lock(DUChain::lock());
522
topLevelContext->squeeze();
523
return topLevelContext;
526
// KDevelop::DUContext* ContextBuilder::buildSubContexts(const HashedString& url, AST *node, KDevelop::DUContext* parent) {
527
// setCompilingContexts(true);
528
// setRecompiling(false);
530
// editor()->setCurrentUrl(url);
532
// node->ducontext = parent;
535
// //copied out of supportBuild
537
// openContext(node->ducontext);
539
// editor()->setCurrentRange(editor()->topRange(EditorIntegrator::DefinitionUseChain));
546
// setCompilingContexts(false);
548
// if( node->ducontext == parent ) {
549
// //The node's du-context should have been replaced!
550
// //Maybe dump the node
551
// kDebug(9007) << "Error in ContextBuilder::buildSubContexts(...): du-context was not replaced with new one";
552
// DUChainWriteLocker lock(DUChain::lock());
553
// delete node->ducontext;
555
// node->ducontext = 0;
558
// return node->ducontext;
561
void ContextBuilder::visitNamespace (NamespaceAST *node)
563
QualifiedIdentifier identifier;
564
if (compilingContexts()) {
565
DUChainReadLocker lock(DUChain::lock());
567
if (node->namespace_name)
568
identifier.push(QualifiedIdentifier(editor()->tokenToString(node->namespace_name)));
571
size_t realStart = node->start_token;
573
if(node->namespace_name) //Move the start behind the name, the simple + hacky way
574
node->start_token = node->namespace_name+1;
576
openContext(node, DUContext::Namespace, identifier);
578
node->start_token = realStart;
580
DefaultVisitor::visitNamespace (node);
585
void ContextBuilder::visitEnumSpecifier(EnumSpecifierAST* node)
587
if(m_onlyComputeSimplified)
590
//The created context must be unnamed, so the enumerators can be found globally with the correct scope
591
openContext(node, DUContext::Enum, 0 );
594
DUChainWriteLocker lock(DUChain::lock());
595
currentContext()->setPropagateDeclarations(true);
598
DefaultVisitor::visitEnumSpecifier(node);
603
void ContextBuilder::classContextOpened(ClassSpecifierAST *node, DUContext* context)
609
void ContextBuilder::visitClassSpecifier (ClassSpecifierAST *node)
611
//We only use the local identifier here, because we build a prefix-context around
612
///@todo think about this.
613
QualifiedIdentifier id;
615
NameCompiler nc(editor()->parseSession());
617
id = nc.identifier();
620
openContext(node, editor()->findRangeForContext(node->name ? node->name->end_token : node->start_token, node->end_token), DUContext::Class, id.isEmpty() ? QualifiedIdentifier() : QualifiedIdentifier(id.last()) );
621
addImportedContexts(); //eventually add template-context
625
int kind = editor()->parseSession()->token_stream->kind(node->class_key);
627
if ((kind == Token_union || id.isEmpty())) {
628
//It's an unnamed union context, or an unnamed struct, propagate the declarations to the parent
629
DUChainWriteLocker lock(DUChain::lock());
631
if(kind == Token_enum || kind == Token_union || m_typeSpecifierWithoutInitDeclarators == node->start_token) {
632
///@todo Mark unions in the duchain in some way, instead of just representing them as a class
633
currentContext()->setInSymbolTable(currentContext()->parentContext()->inSymbolTable());
634
currentContext()->setPropagateDeclarations(true);
639
classContextOpened(node, currentContext());
641
DefaultVisitor::visitClassSpecifier (node);
646
void ContextBuilder::visitTypedef (TypedefAST *node)
648
DefaultVisitor::visitTypedef (node);
650
// Didn't get claimed if it was still set
651
m_importedParentContexts.clear();
654
void ContextBuilder::visitFunctionDefinition (FunctionDefinitionAST *node)
656
PushValue<bool> push(m_inFunctionDefinition, (bool)node->function_body);
658
QualifiedIdentifier functionName;
659
if (compilingContexts() && node->init_declarator && node->init_declarator->declarator && node->init_declarator->declarator->id) {
660
identifierForNode(node->init_declarator->declarator->id, functionName);
662
if (functionName.count() >= 2) {
664
// This is a class function definition
665
DUChainReadLocker lock(DUChain::lock());
666
QualifiedIdentifier currentScope = currentContext()->scopeIdentifier(true);
667
QualifiedIdentifier className = currentScope + functionName;
669
className.setExplicitlyGlobal(true);
671
QList<Declaration*> classDeclarations = currentContext()->findDeclarations(className);
673
if (classDeclarations.count() != 0 && classDeclarations.first()->internalContext()) {
674
queueImportedContext(classDeclarations.first()->internalContext());
676
QualifiedIdentifier newFunctionName(className);
677
newFunctionName.push(functionName.last());
678
if(newFunctionName.count() > currentScope.count())
679
functionName = newFunctionName.mid(currentScope.count());
683
visitFunctionDeclaration(node);
685
if(!m_onlyComputeVisible) { //If we only compute the publically visible, we don't need to go into function bodies
686
m_openingFunctionBody = functionName;
689
if (node->constructor_initializers && node->function_body) {
690
//Since we put the context around the context for the compound statement, it also gets the local scope identifier.
691
openContext(node->constructor_initializers, node->function_body, DUContext::Other, m_openingFunctionBody); //The constructor initializer context
692
addImportedContexts();
693
m_openingFunctionBody = QualifiedIdentifier();
695
// Otherwise, the context is created in the function body visit
697
visit(node->constructor_initializers);
698
visit(node->function_body);
699
m_openingFunctionBody = QualifiedIdentifier();
701
if (node->constructor_initializers) {
706
visit(node->win_decl_specifiers);
707
// If still defined, not needed
708
m_importedParentContexts.clear();
711
void ContextBuilder::visitFunctionDeclaration (FunctionDefinitionAST* node)
713
visit(node->type_specifier);
714
visit(node->init_declarator);
717
DUContext* ContextBuilder::openContextEmpty(AST* rangeNode, DUContext::ContextType type)
719
if (compilingContexts()) {
720
#ifdef DEBUG_UPDATE_MATCHING
721
kDebug() << "opening context with text" << editor()->tokensToStrings( rangeNode->start_token, rangeNode->end_token );
723
KDevelop::SimpleRange range = editor()->findRangeForContext(rangeNode->start_token, rangeNode->end_token);
724
range.end = range.start;
725
DUContext* ret = openContextInternal(range, type, QualifiedIdentifier());
726
rangeNode->ducontext = ret;
730
openContext(rangeNode->ducontext);
732
LockedSmartInterface iface = editor()->smart();
733
editor()->setCurrentRange(iface, currentContext()->smartRange());
735
return currentContext();
739
DUContext* ContextBuilder::openContextInternal(const KDevelop::SimpleRange& range, DUContext::ContextType type, const QualifiedIdentifier& identifier)
741
DUContext* ret = ContextBuilderBase::openContextInternal(range, type, identifier);
744
DUChainWriteLocker lock(DUChain::lock());
745
static_cast<CppDUContext<DUContext>*>(ret)->deleteAllInstantiations();
749
* @todo either remove this here and add it to the correct other places, or remove it in the over places.
750
* The problem: For template-parameter contexts this needs to be imported into function-parameter contexts
751
* and into class-contexts, directly when they are opened. Maybe it is easier leaving it here.
753
addImportedContexts();
758
DUContext* ContextBuilder::newContext(const SimpleRange& range)
760
return new CppDUContext<DUContext>(range, currentContext());
763
#ifdef DEBUG_CONTEXT_RANGES
764
void ContextBuilder::checkRanges()
766
for(QHash<KDevelop::DUContext*, KDevelop::SimpleRange>::iterator it = m_contextRanges.begin(); it != m_contextRanges.end(); ) {
767
if(it.key()->range() != *it) {
768
kDebug(9007) << "Range of" << it.key()->scopeIdentifier(true).toString() << "changed from" << (*it).textRange() << "to" << it.key()->range().textRange() << "at\n" << kBacktrace();
769
it = m_contextRanges.erase(it); //Remove it so we see each change only once
777
void ContextBuilder::visitCompoundStatement(CompoundStatementAST * node)
779
openContext(node, DUContext::Other, m_openingFunctionBody);
780
m_openingFunctionBody.clear();
782
addImportedContexts();
784
DefaultVisitor::visitCompoundStatement(node);
789
void ContextBuilder::preVisitSimpleDeclaration(SimpleDeclarationAST * node) {
790
if(!node->init_declarators && node->type_specifier)
791
m_typeSpecifierWithoutInitDeclarators = node->type_specifier->start_token;
794
void ContextBuilder::visitSimpleDeclaration(SimpleDeclarationAST *node)
796
preVisitSimpleDeclaration(node);
798
DefaultVisitor::visitSimpleDeclaration(node);
800
// Didn't get claimed if it was still set
801
m_importedParentContexts.clear();
804
void ContextBuilder::visitPostSimpleDeclaration(SimpleDeclarationAST*)
806
// Didn't get claimed if it was still set
807
m_importedParentContexts.clear();
810
void ContextBuilder::visitName (NameAST *)
812
// Note: we don't want to visit the name node, the name compiler does that for us (only when we need it)
815
void ContextBuilder::visitUsing(UsingAST* node)
817
// TODO store the using
818
DefaultVisitor::visitUsing(node);
822
* This class is used to decide whether something is an expression or a declaration
823
* Maybe using it is overkill
824
* @todo Check how to do the test fast and correctly
826
class VerifyExpressionVisitor : public Cpp::ExpressionVisitor {
828
VerifyExpressionVisitor(ParseSession* session) : Cpp::ExpressionVisitor(session), result(true) {
830
virtual void problem(AST* /*node*/, const QString& /*str*/) {
837
class IdentifierVerifier : public DefaultVisitor
840
IdentifierVerifier(ContextBuilder* _builder, const SimpleCursor& _cursor)
847
ContextBuilder* builder;
848
bool result; //Will be true when this should be an expression, else false.
851
void visitPostfixExpression(PostfixExpressionAST* node)
853
if( node->expression && node->expression->kind == AST::Kind_PrimaryExpression &&
854
node->sub_expressions ) {
855
const ListNode<ExpressionAST*> *it = node->sub_expressions->toFront(), *end = it;
856
if( it->element && it->element->kind == AST::Kind_FunctionCall && it->next == end ) {
857
///Special-case: We have a primary expression with a function-call, always treat that as an expression.
861
//First evaluate the primary expression, and then pass the result from sub-expression to sub-expression through m_lastType
863
visit(node->expression);
865
if( !node->sub_expressions )
867
visitNodes( this, node->sub_expressions );
870
virtual void visitName (NameAST * node)
873
QualifiedIdentifier id;
874
builder->identifierForNode(node, id);
875
if (!builder->currentContext()->findDeclarations(id, cursor).isEmpty()) {
883
void ContextBuilder::visitExpressionOrDeclarationStatement(ExpressionOrDeclarationStatementAST* node)
885
if(m_onlyComputeSimplified) {
886
visit(node->declaration);
890
DUContext::ContextType type;
892
DUChainReadLocker lock(DUChain::lock());
893
type = currentContext()->type();
897
case DUContext::Global:
898
case DUContext::Namespace:
899
case DUContext::Class:
900
case DUContext::Helper:
901
case DUContext::Enum:
902
visit(node->declaration);
905
case DUContext::Function:
906
case DUContext::Other:
907
if (compilingContexts()) {
908
DUChainReadLocker lock(DUChain::lock());
909
/* VerifyExpressionVisitor iv(editor()->parseSession());
911
node->expression->ducontext = currentContext();
912
iv.parse(node->expression);*/
913
IdentifierVerifier iv(this, SimpleCursor(editor()->findPosition(node->start_token)));
914
iv.visit(node->expression);
915
//kDebug(9007) << editor()->findPosition(node->start_token) << "IdentifierVerifier returned" << iv.result;
916
node->expressionChosen = iv.result;
919
if (node->expressionChosen)
920
visit(node->expression);
922
visit(node->declaration);
924
case DUContext::Template:
929
void ContextBuilder::visitForStatement(ForStatementAST *node)
931
// Not setting the member var because it gets nuked in visitSimpleDeclaration
932
AST* first = node->init_statement;
934
first = node->condition;
936
first = node->expression;
940
AST* second = node->expression;
942
second = node->condition;
944
second = node->init_statement;
946
DUContext* secondParentContext = openContext(first, second, DUContext::Other);
948
visit(node->init_statement);
949
visit(node->condition);
950
visit(node->expression);
954
if (node->statement) {
955
const bool contextNeeded = createContextIfNeeded(node->statement, secondParentContext);
957
visit(node->statement);
963
// Didn't get claimed if it was still set
964
m_importedParentContexts.clear();
967
void ContextBuilder::createTypeForInitializer(InitializerAST* /*node*/) {
970
void ContextBuilder::closeTypeForInitializer(InitializerAST* /*node*/) {
973
void ContextBuilder::createTypeForDeclarator(DeclaratorAST* /*node*/) {
976
void ContextBuilder::closeTypeForDeclarator(DeclaratorAST* /*node*/) {
979
void ContextBuilder::visitParameterDeclarationClause(ParameterDeclarationClauseAST* node)
981
//Don't assign the initializer to parameter-declarations
982
InitializerAST* oldCurrentInitializer = m_currentInitializer;
983
m_currentInitializer = 0;
985
DefaultVisitor::visitParameterDeclarationClause(node);
987
m_currentInitializer = oldCurrentInitializer;
990
void ContextBuilder::visitInitDeclarator(InitDeclaratorAST *node)
992
QualifiedIdentifier id;
993
if(node->declarator && node->declarator->id && node->declarator->id->qualified_names && (!node->declarator->parameter_declaration_clause || node->declarator->parameter_is_initializer)) {
994
//Build a prefix-context for external variable-definitions
995
SimpleCursor pos = editor()->findPosition(node->start_token, KDevelop::EditorIntegrator::FrontEdge);
996
identifierForNode(node->declarator->id, id);
998
openPrefixContext(node, id, pos);
1001
m_currentInitializer = node->initializer;
1002
if(node->declarator)
1003
visitDeclarator(node->declarator);
1004
if(node->initializer)
1005
visitInitializer(node->initializer);
1006
m_currentInitializer = 0;
1008
closePrefixContext(id);
1011
void ContextBuilder::visitDeclarator(DeclaratorAST *node) {
1013
//BEGIN Copied from default visitor
1014
visit(node->sub_declarator);
1015
visitNodes(this, node->ptr_ops);
1017
visit(node->bit_expression);
1018
//END Finished with first part of default visitor
1020
if(m_onlyComputeSimplified)
1023
createTypeForDeclarator(node);
1025
if(m_currentInitializer) //Needs to be visited now, so the type-builder can use the initializer to build a constant integral tyoe
1026
createTypeForInitializer(m_currentInitializer);
1028
if (node->parameter_declaration_clause && (compilingContexts() || node->parameter_declaration_clause->ducontext)) {
1029
DUContext* ctx = openContext(node->parameter_declaration_clause, DUContext::Function, node->id);
1030
addImportedContexts();
1031
if(compilingContexts())
1032
queueImportedContext(ctx);
1035
//BEGIN Copied from default visitor
1036
visitNodes(this, node->array_dimensions);
1037
visit(node->parameter_declaration_clause);
1038
visit(node->exception_spec);
1039
//END Finished with default visitor
1041
if(m_currentInitializer)
1042
closeTypeForInitializer(m_currentInitializer);
1044
closeTypeForDeclarator(node);
1046
if (node->parameter_declaration_clause && (compilingContexts() || node->parameter_declaration_clause->ducontext))
1050
void ContextBuilder::addImportedContexts()
1052
if (compilingContexts() && !m_importedParentContexts.isEmpty()) {
1053
DUChainWriteLocker lock(DUChain::lock());
1055
foreach (const DUContext::Import& imported, m_importedParentContexts)
1056
if(DUContext* imp = imported.context(topContext()))
1057
addImportedParentContextSafely(currentContext(), imp);
1059
//Move on the internal-context of Declarations/Definitions
1060
foreach( const DUContext::Import& importedContext, m_importedParentContexts ) {
1061
if( DUContext* imp = importedContext.context(topContext()) )
1062
if( imp->type() == DUContext::Template || imp->type() == DUContext::Function )
1063
if( imp->owner() && imp->owner()->internalContext() == imp )
1064
imp->owner()->setInternalContext(currentContext());
1067
m_importedParentContexts.clear();
1072
void ContextBuilder::setInSymbolTable(KDevelop::DUContext* context) {
1073
if(context->type() == DUContext::Class) {
1074
//Do not put unnamed/unique structs and all their members into the symbol-table
1075
QualifiedIdentifier scopeId = context->localScopeIdentifier();
1076
if(scopeId.isEmpty() || (scopeId.count() == 1 && scopeId.first().isUnique())) {
1077
context->setInSymbolTable(false);
1081
ContextBuilderBase::setInSymbolTable(context);
1084
void ContextBuilder::visitIfStatement(IfStatementAST* node)
1086
// Not setting the member var because it gets nuked in visitSimpleDeclaration
1087
DUContext* secondParentContext = openContext(node->condition, DUContext::Other);
1089
visit(node->condition);
1093
if (node->statement) {
1094
const bool contextNeeded = createContextIfNeeded(node->statement, secondParentContext);
1096
visit(node->statement);
1102
if (node->else_statement) {
1103
const bool contextNeeded = createContextIfNeeded(node->else_statement, secondParentContext);
1105
visit(node->else_statement);
1112
void ContextBuilder::visitDoStatement(DoStatementAST *node)
1114
if(!node->statement) {
1115
kWarning() << "error, no statement"; //Warning instead of crashing here
1118
//We don't need to create a context for compound-statements, since those create a context by themselves
1119
if(node->statement->kind != AST::Kind_CompoundStatement) {
1120
openContext(node->statement, DUContext::Other);
1122
visit(node->statement);
1126
visit(node->statement);
1129
if (node->expression) {
1130
const bool contextNeeded = createContextIfNeeded(node->expression, lastContext());
1132
visit(node->expression);
1139
void ContextBuilder::visitTryBlockStatement(TryBlockStatementAST *node)
1141
QVector<DUContext::Import> parentContextsToImport = m_importedParentContexts;
1143
if(node->try_block->kind != AST::Kind_CompoundStatement) {
1144
openContext(node->try_block, DUContext::Other, m_openingFunctionBody);
1145
m_openingFunctionBody.clear();
1146
addImportedContexts();
1148
visit(node->try_block);
1152
//Do not double-open a context on the same node, because that will lead to problems in the mapping
1153
//and failures in use-building
1154
visit(node->try_block);
1157
m_tryParentContexts.push(parentContextsToImport);
1159
visitNodes(this, node->catch_blocks);
1161
m_tryParentContexts.pop();
1164
void ContextBuilder::visitCatchStatement(CatchStatementAST *node)
1166
QVector<DUContext::Import> contextsToImport;
1168
if (node->condition) {
1169
DUContext* secondParentContext = openContext(node->condition, DUContext::Other);
1172
DUChainReadLocker lock(DUChain::lock());
1173
contextsToImport.append(DUContext::Import(secondParentContext, 0));
1176
visit(node->condition);
1181
contextsToImport += m_tryParentContexts.top();
1183
if (node->statement) {
1184
const bool contextNeeded = createContextIfNeeded(node->statement, contextsToImport);
1186
visit(node->statement);
1193
bool ContextBuilder::createContextIfNeeded(AST* node, DUContext* importedParentContext)
1195
QVector<DUContext::Import> imports;
1197
DUChainReadLocker lock(DUChain::lock());
1198
imports << DUContext::Import(importedParentContext, 0);
1201
return createContextIfNeeded(node, imports);
1204
bool ContextBuilder::createContextIfNeeded(AST* node, const QVector<DUContext::Import>& importedParentContexts)
1206
m_importedParentContexts = importedParentContexts;
1208
const bool contextNeeded = !ast_cast<CompoundStatementAST*>(node);
1209
if (contextNeeded) {
1210
openContext(node, DUContext::Other);
1211
addImportedContexts();
1213
return contextNeeded;
1216
void ContextBuilder::identifierForNode(NameAST* id, TypeSpecifierAST** typeSpecifier, QualifiedIdentifier& target)
1219
target = QualifiedIdentifier();
1222
m_nameCompiler->run(id, &target);
1224
*typeSpecifier = m_nameCompiler->lastTypeSpecifier();
1227
bool ContextBuilder::smart() const {
1228
return editor()->smart();