KDevelop API Documentation

languages/cpp/cppcodecompletion.cpp

Go to the documentation of this file.
00001 /*************************************************************************** 00002 cppcodecompletion.cpp - description 00003 ------------------- 00004 begin : Sat Jul 21 2001 00005 copyright : (C) 2001 by Victor Röder 00006 email : victor_roeder@gmx.de 00007 copyright : (C) 2002,2003 by Roberto Raggi 00008 email : roberto@kdevelop.org 00009 ***************************************************************************/ 00010 00011 /*************************************************************************** 00012 * * 00013 * This program is free software; you can redistribute it and/or modify * 00014 * it under the terms of the GNU General Public License as published by * 00015 * the Free Software Foundation; either version 2 of the License, or * 00016 * (at your option) any later version. * 00017 * * 00018 ***************************************************************************/ 00019 #include "cppcodecompletion.h" 00020 #include "cppcodecompletionconfig.h" 00021 #include "backgroundparser.h" 00022 #include "ast.h" 00023 #include "ast_utils.h" 00024 #include "codeinformationrepository.h" 00025 #include "parser.h" 00026 #include "lexer.h" 00027 #include "tree_parser.h" 00028 #include "cpp_tags.h" 00029 #include "cppsupport_utils.h" 00030 #include "tag_creator.h" 00031 00032 #include <kapplication.h> 00033 #include <kdebug.h> 00034 #include <klocale.h> 00035 #include <kmainwindow.h> 00036 #include <kmessagebox.h> 00037 #include <kparts/part.h> 00038 #include <kstatusbar.h> 00039 #include <ktexteditor/document.h> 00040 00041 #include <qdatastream.h> 00042 #include <qfile.h> 00043 #include <qmap.h> 00044 #include <qregexp.h> 00045 #include <qstatusbar.h> 00046 #include <qstring.h> 00047 #include <qstringlist.h> 00048 #include <qpair.h> 00049 #include <qvaluestack.h> 00050 00051 #include <kdevpartcontroller.h> 00052 #include <kdevmainwindow.h> 00053 #include <kdevproject.h> 00054 #include <kdevcoderepository.h> 00055 00056 class SimpleVariable 00057 { 00058 public: 00059 SimpleVariable() {} 00060 SimpleVariable( const SimpleVariable& source ) 00061 : name( source.name ), type( source.type ) {} 00062 ~SimpleVariable(){} 00063 00064 SimpleVariable& operator = ( const SimpleVariable& source ){ 00065 name = source.name; 00066 type = source.type; 00067 return *this; 00068 } 00069 00070 QString name; 00071 QStringList type; 00072 }; 00073 00074 class SimpleContext 00075 { 00076 public: 00077 SimpleContext( SimpleContext* prev=0 ) 00078 : m_prev( prev ) {} 00079 00080 virtual ~SimpleContext() 00081 { 00082 if( m_prev ){ 00083 delete( m_prev ); 00084 m_prev = 0; 00085 } 00086 } 00087 00088 SimpleContext* prev() const 00089 { return m_prev; } 00090 00091 void attach( SimpleContext* ctx ) 00092 { m_prev = ctx; } 00093 00094 void detach() 00095 { m_prev = 0; } 00096 00097 const QValueList<SimpleVariable>& vars() const 00098 { return m_vars; } 00099 00100 void add( const SimpleVariable& v ) 00101 { m_vars.append( v ); } 00102 00103 void add( const QValueList<SimpleVariable>& vars ) 00104 { m_vars += vars; } 00105 00106 SimpleVariable findVariable( const QString& varname ) 00107 { 00108 SimpleContext* ctx = this; 00109 while( ctx ){ 00110 const QValueList<SimpleVariable>& vars = ctx->vars(); 00111 for( int i=vars.count() - 1; i>=0; --i ){ 00112 SimpleVariable v = vars[ i ]; 00113 if( v.name == varname ) 00114 return v; 00115 } 00116 ctx = ctx->prev(); 00117 } 00118 return SimpleVariable(); 00119 } 00120 00121 private: 00122 QValueList<SimpleVariable> m_vars; 00123 SimpleContext* m_prev; 00124 }; 00125 00126 struct RecoveryPoint 00127 { 00128 int kind; 00129 QStringList scope; 00130 QValueList<QStringList> imports; 00131 00132 int startLine, startColumn; 00133 int endLine, endColumn; 00134 00135 RecoveryPoint() 00136 : kind( 0 ), startLine( 0 ), startColumn( 0 ), 00137 endLine( 0 ), endColumn( 0 ) 00138 { 00139 } 00140 00141 private: 00142 RecoveryPoint( const RecoveryPoint& source ); 00143 void operator = ( const RecoveryPoint& source ); 00144 }; 00145 00146 struct CppCodeCompletionData 00147 { 00148 QPtrList<RecoveryPoint> recoveryPoints; 00149 QStringList classNameList; 00150 00151 CppCodeCompletionData() 00152 { 00153 recoveryPoints.setAutoDelete( true ); 00154 } 00155 00156 RecoveryPoint* findRecoveryPoint( int line, int column ) 00157 { 00158 if( recoveryPoints.count() == 0 ) 00159 return 0; 00160 00161 QPair<int, int> pt = qMakePair( line, column ); 00162 00163 QPtrListIterator<RecoveryPoint> it( recoveryPoints ); 00164 RecoveryPoint* recPt = 0; 00165 00166 while( it.current() ){ 00167 QPair<int, int> startPt = qMakePair( it.current()->startLine, it.current()->startColumn ); 00168 QPair<int, int> endPt = qMakePair( it.current()->endLine, it.current()->endColumn ); 00169 00170 if( pt < startPt ) 00171 break; 00172 00173 recPt = it.current(); 00174 00175 ++it; 00176 } 00177 00178 return recPt; 00179 } 00180 00181 }; 00182 00183 static QString toSimpleName( NameAST* name ) 00184 { 00185 if( !name ) 00186 return QString::null; 00187 00188 QString s; 00189 QPtrList<ClassOrNamespaceNameAST> l = name->classOrNamespaceNameList(); 00190 QPtrListIterator<ClassOrNamespaceNameAST> nameIt( l ); 00191 while( nameIt.current() ){ 00192 if( nameIt.current()->name() ){ 00193 s += nameIt.current()->name()->text() + "::"; 00194 } 00195 ++nameIt; 00196 } 00197 00198 if( name->unqualifiedName() && name->unqualifiedName()->name() ) 00199 s += name->unqualifiedName()->name()->text(); 00200 00201 return s; 00202 } 00203 00204 bool operator < ( const KTextEditor::CompletionEntry& e1, const KTextEditor::CompletionEntry& e2 ) 00205 { 00206 return e1.text < e2.text; 00207 } 00208 00209 static QValueList<KTextEditor::CompletionEntry> unique( const QValueList<KTextEditor::CompletionEntry>& entryList ) 00210 { 00211 00212 QValueList< KTextEditor::CompletionEntry > l; 00213 QMap<QString, bool> map; 00214 QValueList< KTextEditor::CompletionEntry >::ConstIterator it=entryList.begin(); 00215 while( it != entryList.end() ){ 00216 KTextEditor::CompletionEntry e = *it++; 00217 QString key = (e.type + " " + 00218 e.prefix + " " + 00219 e.text + " " + 00220 e.postfix + " ").simplifyWhiteSpace().stripWhiteSpace(); 00221 if( map.find(key) == map.end() ){ 00222 map[ key ] = TRUE; 00223 l << e; 00224 } 00225 } 00226 return l; 00227 } 00228 00229 static QStringList unique( const QStringList& entryList ) 00230 { 00231 00232 QStringList l; 00233 QMap<QString, bool> map; 00234 QStringList::ConstIterator it=entryList.begin(); 00235 while( it != entryList.end() ){ 00236 QString e = *it++; 00237 if( map.find(e) == map.end() ){ 00238 map[ e ] = TRUE; 00239 l << e; 00240 } 00241 } 00242 return l; 00243 } 00244 00245 CppCodeCompletion::CppCodeCompletion( CppSupportPart* part ) 00246 : d( new CppCodeCompletionData ), m_includeRx( "^\\s*#\\s*include\\s+[\"<]" ) 00247 { 00248 m_pSupport = part; 00249 00250 m_activeCursor = 0; 00251 m_activeEditor = 0; 00252 m_activeCompletion = 0; 00253 m_ccTimer = new QTimer( this ); 00254 m_ccLine = 0; 00255 m_ccColumn = 0; 00256 connect( m_ccTimer, SIGNAL(timeout()), this, SLOT(slotTimeout()) ); 00257 00258 computeFileEntryList(); 00259 00260 CppSupportPart* cppSupport = m_pSupport; 00261 connect( cppSupport->project(), SIGNAL(addedFilesToProject(const QStringList& )), this, SLOT(computeFileEntryList()) ); 00262 connect( cppSupport->project(), SIGNAL(removedFilesFromProject(const QStringList& )), this, SLOT(computeFileEntryList()) ); 00263 00264 m_bArgHintShow = false; 00265 m_bCompletionBoxShow = false; 00266 m_completionMode = NormalCompletion; 00267 00268 m_repository = new CodeInformationRepository( cppSupport->codeRepository() ); 00269 setupCodeInformationRepository(); 00270 00271 if( part->partController()->parts() ) 00272 { 00273 QPtrListIterator<KParts::Part> it( *part->partController()->parts() ); 00274 while( KParts::Part* part = it.current() ) 00275 { 00276 integratePart( part ); 00277 ++it; 00278 } 00279 } 00280 00281 if( part->partController()->activePart() ) 00282 slotActivePartChanged( part->partController()->activePart() ); 00283 00284 connect( part->partController( ), SIGNAL( partAdded( KParts::Part* ) ), 00285 this, SLOT( slotPartAdded( KParts::Part* ) ) ); 00286 connect( part->partController( ), SIGNAL( activePartChanged( KParts::Part* ) ), 00287 this, SLOT( slotActivePartChanged( KParts::Part* ) ) ); 00288 00289 connect( part, SIGNAL(fileParsed(const QString&)), this, SLOT(slotFileParsed(const QString&)) ); 00290 } 00291 00292 CppCodeCompletion::~CppCodeCompletion( ) 00293 { 00294 delete( m_repository ); 00295 delete( d ); 00296 } 00297 00298 void CppCodeCompletion::slotTimeout() 00299 { 00300 if( !m_activeCursor || !m_activeEditor || !m_activeCompletion ) 00301 return; 00302 00303 uint nLine, nCol; 00304 m_activeCursor->cursorPositionReal( &nLine, &nCol ); 00305 00306 if( nLine != m_ccLine || nCol != m_ccColumn ) 00307 return;; 00308 00309 QString textLine = m_activeEditor->textLine( nLine ); 00310 QChar ch = textLine[ nCol ];; 00311 if( ch.isLetterOrNumber() || ch == '_' ) 00312 return; 00313 00314 completeText(); 00315 } 00316 00317 void CppCodeCompletion::slotArgHintHided( ) 00318 { 00319 //kdDebug(9007) << "CppCodeCompletion::slotArgHintHided()" << endl; 00320 m_bArgHintShow = false; 00321 } 00322 00323 void CppCodeCompletion::slotCompletionBoxHided( KTextEditor::CompletionEntry entry ) 00324 { 00325 Q_UNUSED( entry ); 00326 m_bCompletionBoxShow = false; 00327 } 00328 00329 void CppCodeCompletion::integratePart( KParts::Part* part ) 00330 { 00331 if( !part || !part->widget() ) 00332 return; 00333 00334 if( KTextEditor::Document* doc = dynamic_cast<KTextEditor::Document*>( part ) ) 00335 { 00336 kdDebug(9007) << "=================> integrate document: " << doc << endl; 00337 00338 if( m_pSupport && m_pSupport->codeCompletionConfig()->automaticCodeCompletion() ){ 00339 kdDebug( 9007 ) << "enabling code completion" << endl; 00340 connect(part, SIGNAL(textChanged()), this, SLOT(slotTextChanged()) ); 00341 connect(part->widget(), SIGNAL( completionDone( KTextEditor::CompletionEntry ) ), this, 00342 SLOT( slotCompletionBoxHided( KTextEditor::CompletionEntry ) ) ); 00343 connect(part->widget(), SIGNAL( argHintHidden() ), this, 00344 SLOT( slotArgHintHided() ) ); 00345 } 00346 00347 } 00348 } 00349 00350 void CppCodeCompletion::slotPartAdded(KParts::Part *part) 00351 { 00352 integratePart( part ); 00353 } 00354 00355 void CppCodeCompletion::slotActivePartChanged(KParts::Part *part) 00356 { 00357 kdDebug( 9007 ) << "CppCodeCompletion::slotActivePartChanged()" << endl; 00358 00359 if( !part ) 00360 return; 00361 00362 m_activeFileName = QString::null; 00363 00364 KTextEditor::Document* doc = dynamic_cast<KTextEditor::Document*>( part ); 00365 if( !doc ) 00366 return; 00367 00368 m_activeFileName = doc->url().path(); 00369 00370 // if the interface stuff fails we should disable codecompletion automatically 00371 m_activeEditor = dynamic_cast<KTextEditor::EditInterface*>(part); 00372 if( !m_activeEditor ){ 00373 kdDebug( 9007 ) << "Editor doesn't support the EditDocumentIface" << endl; 00374 return; 00375 } 00376 00377 m_activeCursor = dynamic_cast<KTextEditor::ViewCursorInterface*>(part->widget()); 00378 if( !m_activeCursor ){ 00379 kdDebug( 9007 ) << "The editor doesn't support the CursorDocumentIface!" << endl; 00380 return; 00381 } 00382 00383 m_activeCompletion = dynamic_cast<KTextEditor::CodeCompletionInterface*>(part->widget()); 00384 if( !m_activeCompletion ){ 00385 kdDebug( 9007 ) << "Editor doesn't support the CompletionIface" << endl; 00386 return; 00387 } 00388 00389 kdDebug(9007) << "CppCodeCompletion::slotActivePartChanged() -- end" << endl; 00390 } 00391 00392 void CppCodeCompletion::slotTextChanged() 00393 { 00394 m_ccTimer->stop(); 00395 00396 if( !m_activeCursor ) 00397 return; 00398 00399 unsigned int nLine, nCol; 00400 m_activeCursor->cursorPositionReal( &nLine, &nCol ); 00401 00402 QString strCurLine = m_activeEditor->textLine( nLine ); 00403 QString ch = strCurLine.mid( nCol-1, 1 ); 00404 QString ch2 = strCurLine.mid( nCol-2, 2 ); 00405 00406 m_ccLine = 0; 00407 m_ccColumn = 0; 00408 00409 if( (m_pSupport->codeCompletionConfig()->automaticCodeCompletion() && (ch == "." || ch2 == "->" || ch2 == "::")) || 00410 (m_pSupport->codeCompletionConfig()->automaticArgumentsHint() && ch == "(") || 00411 (m_pSupport->codeCompletionConfig()->automaticHeaderCompletion() && (ch == "\"" || ch == "<") && m_includeRx.search(strCurLine) != -1 ) ){ 00412 m_ccLine = nLine; 00413 m_ccColumn = nCol; 00414 m_ccTimer->start( ch == "(" ? m_pSupport->codeCompletionConfig()->argumentsHintDelay() : m_pSupport->codeCompletionConfig()->codeCompletionDelay(), true ); 00415 } 00416 } 00417 00418 enum { T_ACCESS, T_PAREN, T_BRACKET, T_IDE, T_UNKNOWN }; 00419 00420 int CppCodeCompletion::expressionAt( const QString& text, int index ) 00421 { 00422 kdDebug(9007) << "CppCodeCompletion::expressionAt()" << endl; 00423 00424 int last = T_UNKNOWN; 00425 int start = index; 00426 while( index > 0 ){ 00427 while( index > 0 && text[index].isSpace() ){ 00428 --index; 00429 } 00430 00431 QChar ch = text[ index ]; 00432 QString ch2 = text.mid( index-1, 2 ); 00433 if( (last != T_IDE) && (ch.isLetterOrNumber() || ch == '_') ){ 00434 while( index > 0 && (text[index].isLetterOrNumber() || text[index] == '_') ){ 00435 --index; 00436 } 00437 last = T_IDE; 00438 } else if( last != T_IDE && ch == ')' ){ 00439 int count = 0; 00440 while( index > 0 ){ 00441 QChar ch = text[ index ]; 00442 if( ch == '(' ){ 00443 ++count; 00444 } else if( ch == ')' ){ 00445 --count; 00446 } else if( count == 0 ){ 00447 --index; 00448 last = T_PAREN; 00449 break; 00450 } 00451 --index; 00452 } 00453 } else if( ch == ']' ){ 00454 int count = 0; 00455 while( index > 0 ){ 00456 QChar ch = text[ index ]; 00457 if( ch == '[' ){ 00458 ++count; 00459 } else if( ch == ']' ){ 00460 --count; 00461 } else if( count == 0 ){ 00462 --index; 00463 last = T_BRACKET; 00464 break; 00465 } 00466 --index; 00467 } 00468 } else if( ch == '.' ){ 00469 --index; 00470 last = T_ACCESS; 00471 } else if( ch2 == "::" ){ 00472 index -= 2; 00473 last = T_ACCESS; 00474 } else if( ch2 == "->" ){ 00475 index -= 2; 00476 last = T_ACCESS; 00477 } else { 00478 if( start > index ){ 00479 ++index; 00480 } 00481 last = T_UNKNOWN; 00482 break; 00483 } 00484 } 00485 return index; 00486 } 00487 00488 QStringList CppCodeCompletion::splitExpression( const QString& text ) 00489 { 00490 #define ADD_CURRENT()\ 00491 if( current.length() ) { l << current; /*kdDebug(9007) << "add word " << current << endl;*/ current = ""; } 00492 00493 QStringList l; 00494 int index = 0; 00495 QString current; 00496 while( index < (int)text.length() ){ 00497 QChar ch = text[ index ]; 00498 QString ch2 = text.mid( index, 2 ); 00499 00500 if( ch == '.' ){ 00501 ADD_CURRENT(); 00502 ++index; 00503 } else if( ch == '(' ){ 00504 int count = 0; 00505 while( index < (int)text.length() ){ 00506 QChar ch = text[ index ]; 00507 if( ch == '(' ){ 00508 ++count; 00509 } else if( ch == ')' ){ 00510 --count; 00511 } else if( count == 0 ){ 00512 break; 00513 } 00514 current += ch; 00515 ++index; 00516 } 00517 } else if( ch == '[' ){ 00518 int count = 0; 00519 while( index < (int)text.length() ){ 00520 QChar ch = text[ index ]; 00521 if( ch == '[' ){ 00522 ++count; 00523 } else if( ch == ']' ){ 00524 --count; 00525 } else if( count == 0 ){ 00526 break; 00527 } 00528 current += ch; 00529 ++index; 00530 } 00531 } else if( ch2 == "->" ){ 00532 ADD_CURRENT(); 00533 index += 2; 00534 } else { 00535 current += text[ index ]; 00536 ++index; 00537 } 00538 } 00539 ADD_CURRENT(); 00540 return l; 00541 } 00542 00543 QStringList CppCodeCompletion::evaluateExpression( QString expr, SimpleContext* ctx ) 00544 { 00545 d->classNameList = typeNameList( m_pSupport->codeModel() ); 00546 00547 bool global = false; 00548 if( expr.startsWith("::") ){ 00549 expr = expr.mid( 2 ); 00550 global = true; 00551 } 00552 00553 QStringList exprList = splitExpression( expr ); 00554 QStringList type = evaluateExpressionInternal( exprList, QStringList(), ctx ); 00555 00556 m_pSupport->mainWindow()->statusBar()->message( i18n("Type of %1 is %2").arg(expr).arg(type.join("::")), 1000 ); 00557 00558 QMap<QString, bool> visited; 00559 bool isTypedef = true; 00560 00561 while( isTypedef && !type.isEmpty() ) { 00562 // check if the evaluateded type is a typedef 00563 QValueList<Catalog::QueryArgument> args; 00564 args << Catalog::QueryArgument( "kind", Tag::Kind_Typedef ); 00565 args << Catalog::QueryArgument( "name", type.last() ); 00566 QValueList<Tag> tags = m_repository->query( args ); 00567 isTypedef = !tags.isEmpty() && !visited.contains( type.last() ); 00568 00569 if( isTypedef ) { 00570 visited[ type.last() ] = true; 00571 00572 bool found = false; 00573 for( QValueList<Tag>::Iterator it=tags.begin(); it!=tags.end(); ++it ) { 00574 Tag& tag = *it; 00575 00576 QStringList tp = type; 00577 tp.pop_back(); 00578 00579 QString typeScope = tp.join( "::" ); 00580 QString tagScope = tag.scope().join( "::" ); 00581 00582 //kdDebug(9007) << "=========> typeScope: " << typeScope << endl; 00583 //kdDebug(9007) << "=========> tagScope: " << tagScope << endl; 00584 00585 if( typeScope.endsWith(tagScope) ) { 00586 type = typeName( tag.attribute("t").toString() ); 00587 found = true; 00588 break; 00589 } 00590 } 00591 00592 if( !found ) 00593 type = typeName( tags[0].attribute("t").toString() ); 00594 } 00595 } 00596 00597 return type; 00598 } 00599 00600 QStringList CppCodeCompletion::evaluateExpressionInternal( QStringList & exprList, const QStringList & scope, SimpleContext * ctx ) 00601 { 00602 //kdDebug(9007) << "evaluateExpression " << exprList << " in " << scope << endl; 00603 00604 if( exprList.isEmpty() ) 00605 return scope; 00606 00607 QString currentExpr = exprList.front().stripWhiteSpace(); 00608 exprList.pop_front(); 00609 00610 int leftParen = currentExpr.find( "(" ); 00611 00612 if( leftParen != -1 ) 00613 currentExpr = currentExpr.left( leftParen ).stripWhiteSpace(); 00614 00615 if( currentExpr.contains("::") ){ 00616 if( currentExpr.endsWith("::") ) 00617 currentExpr.truncate( currentExpr.length() - 2 ); 00618 00619 QStringList type = typeName( currentExpr ); 00620 if( !type.isEmpty() ){ 00621 if( leftParen != -1 ){ 00622 QString name = type.back(); 00623 type.pop_back(); 00624 type = typeOf( name, type ); 00625 } 00626 00627 if( !type.isEmpty() ) 00628 return evaluateExpressionInternal( exprList, type ); 00629 } 00630 } 00631 00632 if( ctx ){ 00633 // find the variable type in the current context 00634 QStringList type = ctx->findVariable( currentExpr ).type; 00635 if( !type.isEmpty() ) 00636 return evaluateExpressionInternal( exprList, type ); 00637 00638 QStringList t_this = ctx->findVariable( "this" ).type; 00639 if( !t_this.isEmpty() ){ 00640 QStringList type = typeOf( currentExpr, t_this ); 00641 if( !type.isEmpty() ) 00642 return evaluateExpressionInternal( exprList, type ); 00643 00644 return QStringList(); 00645 } 00646 } 00647 00648 QStringList type = typeOf( currentExpr, scope ); 00649 if( !type.isEmpty() ) 00650 return evaluateExpressionInternal( exprList, type ); 00651 00652 return QStringList(); 00653 } 00654 00655 void 00656 CppCodeCompletion::completeText( ) 00657 { 00658 kdDebug(9007) << "CppCodeCompletion::completeText()" << endl; 00659 00660 if( !m_pSupport || !m_activeCursor || !m_activeEditor || !m_activeCompletion ) 00661 return; 00662 00663 unsigned int line, column; 00664 m_activeCursor->cursorPositionReal( &line, &column ); 00665 00666 int nLine = line, nCol = column; 00667 00668 QString strCurLine = m_activeEditor->textLine( nLine ); 00669 00670 QString ch = strCurLine.mid( nCol-1, 1 ); 00671 QString ch2 = strCurLine.mid( nCol-2, 2 ); 00672 00673 if( m_includeRx.search(strCurLine) != -1 ){ 00674 if( !m_fileEntryList.isEmpty() ){ 00675 m_activeCompletion->showCompletionBox( m_fileEntryList, column - m_includeRx.matchedLength() ); 00676 } 00677 return; 00678 } 00679 00680 bool showArguments = false; 00681 bool isInstance = true; 00682 m_completionMode = NormalCompletion; 00683 00684 if( ch2 == "->" || ch == "." || ch == "(" ){ 00685 int pos = ch2 == "->" ? nCol - 3 : nCol - 2; 00686 QChar c = strCurLine[ pos ]; 00687 while( pos > 0 && c.isSpace() ) 00688 c = strCurLine[ --pos ]; 00689 00690 if( !(c.isLetterOrNumber() || c == '_' || c == ')') ) 00691 return; 00692 } 00693 00694 if( ch == "(" ){ 00695 --nCol; 00696 while( nCol > 0 && strCurLine[nCol].isSpace() ) 00697 --nCol; 00698 00699 showArguments = TRUE; 00700 } 00701 00702 QStringList type, this_type; 00703 QString expr, word; 00704 00705 DeclarationAST::Node recoveredDecl; 00706 00707 SimpleContext* ctx = 0; 00708 00709 m_pSupport->backgroundParser()->lock(); 00710 00711 if( RecoveryPoint* recoveryPoint = d->findRecoveryPoint(line, column) ){ 00712 kdDebug(9007) << "node-kind = " << recoveryPoint->kind << endl; 00713 kdDebug(9007) << "isFunDef = " << (recoveryPoint->kind == NodeType_FunctionDefinition) << endl; 00714 00715 QString textLine = m_activeEditor->textLine( recoveryPoint->startLine ); 00716 kdDebug(9007) << "startLine = " << textLine << endl; 00717 kdDebug(9007) << "node-kind = " << recoveryPoint->kind << endl; 00718 00719 if( recoveryPoint->kind == NodeType_FunctionDefinition ){ 00720 00721 QString textToReparse = getText( recoveryPoint->startLine, recoveryPoint->startColumn, 00722 line, showArguments ? column-1 : column ); 00723 //kdDebug(9007) << "-------------> please reparse only text" << endl << textToReparse << endl 00724 // << "--------------------------------------------" << endl; 00725 00726 Driver d; 00727 Lexer lexer( &d ); 00729 00730 lexer.setSource( textToReparse ); 00731 Parser parser( &d, &lexer ); 00732 00733 parser.parseDeclaration( recoveredDecl ); 00734 //kdDebug(9007) << "recoveredDecl = " << recoveredDecl.get() << endl; 00735 if( recoveredDecl.get() ){ 00736 00737 bool isFunDef = recoveredDecl->nodeType() == NodeType_FunctionDefinition; 00738 kdDebug(9007) << "is function definition = " << isFunDef << endl; 00739 00740 int endLine, endColumn; 00741 recoveredDecl->getEndPosition( &endLine, &endColumn ); 00742 kdDebug(9007) << "endLine = " << endLine << ", endColumn " << endColumn << endl; 00743 00745 00746 if( isFunDef ) { 00747 FunctionDefinitionAST* def = static_cast<FunctionDefinitionAST*>( recoveredDecl.get() ); 00748 00750 00751 QString contents = textToReparse; 00752 int start_expr = expressionAt( contents, contents.length() - 1 ); 00753 00754 // kdDebug(9007) << "start_expr = " << start_expr << endl; 00755 if( start_expr != int(contents.length()) - 1 ) 00756 expr = contents.mid( start_expr, contents.length() - start_expr ).stripWhiteSpace(); 00757 00758 if( expr.startsWith("SIGNAL") || expr.startsWith("SLOT") ){ 00759 m_completionMode = expr.startsWith("SIGNAL") ? SignalCompletion : SlotCompletion; 00760 00761 showArguments = false; 00762 int end_expr = start_expr - 1; 00763 while( end_expr > 0 && contents[end_expr].isSpace() ) 00764 --end_expr; 00765 00766 if( contents[end_expr] != ',' ){ 00767 expr = QString::null; 00768 } else { 00769 --end_expr; 00770 start_expr = expressionAt( contents, end_expr ); 00771 expr = contents.mid( start_expr, end_expr - start_expr + 1 ).stripWhiteSpace(); 00772 } 00773 } else { 00774 int idx = expr.length() - 1; 00775 while( expr[idx].isLetterOrNumber() || expr[idx] == '_' ) 00776 --idx; 00777 00778 if( idx != int(expr.length()) - 1 ){ 00779 ++idx; 00780 word = expr.mid( idx ).stripWhiteSpace(); 00781 expr = expr.left( idx ).stripWhiteSpace(); 00782 } 00783 } 00784 00785 ctx = computeContext( def, endLine, endColumn ); 00786 DeclaratorAST* d = def->initDeclarator()->declarator(); 00787 NameAST* name = d->declaratorId(); 00788 QString scope = recoveryPoint->scope.join( "::" ); 00789 00790 QStringList nested; 00791 00792 QPtrList<ClassOrNamespaceNameAST> l; 00793 if ( name ) 00794 { 00795 l = name->classOrNamespaceNameList(); 00796 } 00797 // QPtrList<ClassOrNamespaceNameAST> l = name->classOrNamespaceNameList(); 00798 QPtrListIterator<ClassOrNamespaceNameAST> nameIt( l ); 00799 while( nameIt.current() ){ 00800 if( nameIt.current()->name() ){ 00801 nested << nameIt.current()->name()->text(); 00802 } 00803 ++nameIt; 00804 } 00805 00806 QString s = nested.join( "::" ); 00807 00808 if( !scope.isEmpty() ){ 00809 scope += QString::fromLatin1( "::" ) + s; 00810 } else { 00811 scope += s; 00812 } 00813 00814 if( scope.endsWith("::") ){ 00815 scope = scope.left( scope.length() - 2 ); 00816 } 00817 00818 if( scope.startsWith("::") ){ 00819 scope = scope.mid( 2 ); 00820 } 00821 00822 if( !scope.isEmpty() ){ 00823 SimpleVariable var; 00824 this_type = typeName( scope ); 00825 var.type = this_type; 00826 var.name = "this"; 00827 ctx->add( var ); 00828 } 00829 00830 type = evaluateExpression( expr, ctx ); 00831 } 00832 } else { 00833 kdDebug(9007) << "no valid declaration to recover!!!" << endl; 00834 } 00835 } 00836 } 00837 00838 if( !recoveredDecl.get() ){ 00839 TranslationUnitAST* ast = m_pSupport->backgroundParser()->translationUnit( m_activeFileName ); 00840 if( AST* node = findNodeAt(ast, line, column) ){ 00841 00842 kdDebug(9007) << "------------------- AST FOUND --------------------" << endl; 00843 00844 if( FunctionDefinitionAST* def = functionDefinition(node) ){ 00845 00846 kdDebug(9007) << "------> found a function definition" << endl; 00847 00848 int startLine, startColumn; 00849 def->getStartPosition( &startLine, &startColumn ); 00850 00851 QString contents = getText( startLine, startColumn, line, showArguments ? column-1 : column ); 00852 00853 00855 int start_expr = expressionAt( contents, contents.length() - 1 ); 00856 00857 // kdDebug(9007) << "start_expr = " << start_expr << endl; 00858 if( start_expr != int(contents.length()) - 1 ) 00859 expr = contents.mid( start_expr, contents.length() - start_expr ).stripWhiteSpace(); 00860 00861 if( expr.startsWith("SIGNAL") || expr.startsWith("SLOT") ){ 00862 m_completionMode = expr.startsWith("SIGNAL") ? SignalCompletion : SlotCompletion; 00863 00864 showArguments = false; 00865 int end_expr = start_expr - 1; 00866 while( end_expr > 0 && contents[end_expr].isSpace() ) 00867 --end_expr; 00868 00869 if( contents[end_expr] != ',' ){ 00870 expr = QString::null; 00871 } else { 00872 --end_expr; 00873 start_expr = expressionAt( contents, end_expr ); 00874 expr = contents.mid( start_expr, end_expr - start_expr + 1 ).stripWhiteSpace(); 00875 } 00876 } else { 00877 int idx = expr.length() - 1; 00878 while( expr[idx].isLetterOrNumber() || expr[idx] == '_' ) 00879 --idx; 00880 00881 if( idx != int(expr.length()) - 1 ){ 00882 ++idx; 00883 word = expr.mid( idx ).stripWhiteSpace(); 00884 expr = expr.left( idx ).stripWhiteSpace(); 00885 } 00886 } 00887 00888 ctx = computeContext( def, line, column ); 00889 00890 QStringList scope; 00891 scopeOfNode( def, scope ); 00892 this_type = scope; 00893 00894 if( scope.size() ){ 00895 SimpleVariable var; 00896 var.type = scope; 00897 var.name = "this"; 00898 ctx->add( var ); 00899 //kdDebug(9007) << "add variable " << var.name << " with type " << var.type << endl; 00900 } 00901 00902 type = evaluateExpression( expr, ctx ); 00903 } 00904 } 00905 } 00906 m_pSupport->backgroundParser()->unlock(); 00907 00908 if( !ctx ) 00909 return; 00910 00911 if( ch2 == "::" || expr.isEmpty() ){ 00912 isInstance = false; 00913 } 00914 00915 kdDebug(9007) << "===========================> type is: " << type.join(" ") << endl; 00916 kdDebug(9007) << "===========================> word is: " << word << endl; 00917 00918 if( !showArguments ){ 00919 QValueList<KTextEditor::CompletionEntry> entryList; 00920 00921 if( type.isEmpty() && expr.isEmpty() ){ 00922 computeCompletionEntryList( entryList, ctx, isInstance ); 00923 computeCompletionEntryList( entryList, m_pSupport->codeModel()->globalNamespace(), isInstance ); 00924 00925 if( m_pSupport->codeCompletionConfig()->includeGlobalFunctions() ) 00926 computeCompletionEntryList( entryList, QStringList(), false ); 00927 00928 if( this_type.size() ) 00929 computeCompletionEntryList( entryList, this_type, isInstance ); 00930 00931 } else if( !type.isEmpty() ){ 00932 computeCompletionEntryList( entryList, type, isInstance ); 00933 } 00934 00935 if( entryList.size() ){ 00936 entryList = unique( entryList ); 00937 #if KDE_VERSION > 305 00938 qHeapSort( entryList ); 00939 #else 00940 // @todo 00941 #endif 00942 m_activeCompletion->showCompletionBox( entryList, word.length() ); 00943 } 00944 } else { 00945 QStringList signatureList; 00946 00947 if( type.isEmpty() && expr.isEmpty() ){ 00948 computeSignatureList( signatureList, word, m_pSupport->codeModel()->globalNamespace()->functionList() ); 00949 computeSignatureList( signatureList, word, QStringList() ); 00950 00951 if( !word.isEmpty() ){ 00952 QStringList fakeType; 00953 fakeType << word; 00954 computeSignatureList( signatureList, word, fakeType ); 00955 } 00956 } else if( !type.isEmpty() ){ 00957 computeSignatureList( signatureList, word, type ); 00958 } 00959 00960 if( !this_type.isEmpty() && expr.isEmpty() ) 00961 computeSignatureList( signatureList, word, this_type ); 00962 00963 if( !signatureList.isEmpty() ){ 00964 signatureList = unique( signatureList ); 00965 qHeapSort( signatureList ); 00966 m_activeCompletion->showArgHint( signatureList, "()", "," ); 00967 } 00968 } 00969 00970 delete( ctx ); 00971 ctx = 0; 00972 } 00973 00974 void CppCodeCompletion::slotFileParsed( const QString& fileName ) 00975 { 00976 if( fileName != m_activeFileName || !m_pSupport || !m_activeEditor ) 00977 return; 00978 00979 m_pSupport->backgroundParser()->lock(); 00980 computeRecoveryPoints(); 00981 m_pSupport->backgroundParser()->unlock(); 00982 } 00983 00984 QStringList CppCodeCompletion::typeOf( const QString& name, const QStringList& scope ) 00985 { 00986 QStringList type; 00987 00988 if( name.isEmpty() ) 00989 return type; 00990 00991 QString key = findClass( scope.join( "::" ) ); 00992 ClassDom klass = findContainer( key ); 00993 if( klass ){ 00994 return typeOf( name, klass ); 00995 } else { 00996 type = typeOf( name, m_pSupport->codeModel()->globalNamespace() ); 00997 if( !type.isEmpty() ) 00998 return type; 00999 } 01000 01001 QValueList<Catalog::QueryArgument> args; 01002 QTime t; 01003 01004 t.start(); 01005 args << Catalog::QueryArgument( "scope", scope ); 01006 /* if( name.length() >=2 ) 01007 args << Catalog::QueryArgument( "prefix", name.left(2) );*/ 01008 args << Catalog::QueryArgument( "name", name ); 01009 QValueList<Tag> tags( m_repository->query(args) ); 01010 kdDebug(9007) << "type of " << name << " in " << scope.join("::") << " takes " << t.elapsed() << endl; 01011 type = typeOf( tags ); 01012 01013 if( type.isEmpty() ){ 01014 // try with parents 01015 t.restart(); 01016 QValueList<Tag> parents( m_repository->getBaseClassList( scope.join("::") ) ); 01017 kdDebug(9007) << "get parents of " << scope.join("::") << " takes " << t.elapsed() << endl; 01018 QValueList<Tag>::Iterator it = parents.begin(); 01019 while( it != parents.end() ){ 01020 Tag& tag = *it; 01021 ++it; 01022 01023 CppBaseClass<Tag> info( tag ); 01024 01025 QStringList newScope = typeName( info.baseClass() ); 01026 type = typeOf( name, newScope ); 01027 if( !type.isEmpty() ) 01028 break; 01029 } 01030 } 01031 01032 return type; 01033 } 01034 01035 void CppCodeCompletion::setupCodeInformationRepository( ) 01036 { 01037 } 01038 01039 QStringList CppCodeCompletion::typeName( const QString& str ) 01040 { 01041 if( str.isEmpty() ) 01042 return QStringList(); 01043 01044 Driver d; 01045 Lexer lex( &d ); 01046 lex.setSource( str ); 01047 Parser parser( &d, &lex ); 01048 01049 TypeSpecifierAST::Node typeSpec; 01050 if( parser.parseTypeSpecifier(typeSpec) ){ 01051 NameAST* name = typeSpec->name(); 01052 01053 QPtrList<ClassOrNamespaceNameAST> l = name->classOrNamespaceNameList(); 01054 QPtrListIterator<ClassOrNamespaceNameAST> it( l ); 01055 01056 QString type; 01057 while( it.current() ){ 01058 if( it.current()->name() ){ 01059 type += it.current()->name()->text() + "::"; 01060 } 01061 ++it; 01062 } 01063 01064 if( name->unqualifiedName() && name->unqualifiedName()->name() ){ 01065 type += name->unqualifiedName()->name()->text(); 01066 } 01067 01068 return QStringList::split( "::", type ); 01069 } 01070 01071 return QStringList(); 01072 } 01073 01074 SimpleContext* CppCodeCompletion::computeContext( FunctionDefinitionAST * ast, int line, int col ) 01075 { 01076 kdDebug(9007) << "CppCodeCompletion::computeContext() -- main" << endl; 01077 01078 SimpleContext* ctx = new SimpleContext(); 01079 01080 if( ast && ast->initDeclarator() && ast->initDeclarator()->declarator() ){ 01081 DeclaratorAST* d = ast->initDeclarator()->declarator(); 01082 if( ParameterDeclarationClauseAST* clause = d->parameterDeclarationClause() ){ 01083 if( ParameterDeclarationListAST* params = clause->parameterDeclarationList() ){ 01084 QPtrList<ParameterDeclarationAST> l( params->parameterList() ); 01085 QPtrListIterator<ParameterDeclarationAST> it( l ); 01086 while( it.current() ){ 01087 ParameterDeclarationAST* param = it.current(); 01088 ++it; 01089 01090 SimpleVariable var; 01091 var.type = typeName( param->typeSpec()->text() ); 01092 var.name = declaratorToString( param->declarator(), QString::null, true ); 01093 01094 if( !var.type.isEmpty() ){ 01095 ctx->add( var ); 01096 //kdDebug(9007) << "add argument " << var.name << " with type " << var.type << endl; 01097 } 01098 } 01099 } 01100 } 01101 } 01102 01103 computeContext( ctx, ast->functionBody(), line, col ); 01104 return ctx; 01105 } 01106 01107 void CppCodeCompletion::computeContext( SimpleContext*& ctx, StatementAST* stmt, int line, int col ) 01108 { 01109 if( !stmt ) 01110 return; 01111 01112 switch( stmt->nodeType() ) 01113 { 01114 case NodeType_IfStatement: 01115 computeContext( ctx, static_cast<IfStatementAST*>(stmt), line, col ); 01116 break; 01117 case NodeType_WhileStatement: 01118 computeContext( ctx, static_cast<WhileStatementAST*>(stmt), line, col ); 01119 break; 01120 case NodeType_DoStatement: 01121 computeContext( ctx, static_cast<DoStatementAST*>(stmt), line, col ); 01122 break; 01123 case NodeType_ForStatement: 01124 computeContext( ctx, static_cast<ForStatementAST*>(stmt), line, col ); 01125 break; 01126 case NodeType_SwitchStatement: 01127 computeContext( ctx, static_cast<SwitchStatementAST*>(stmt), line, col ); 01128 break; 01129 case NodeType_DeclarationStatement: 01130 computeContext( ctx, static_cast<DeclarationStatementAST*>(stmt), line, col ); 01131 break; 01132 case NodeType_StatementList: 01133 computeContext( ctx, static_cast<StatementListAST*>(stmt), line, col ); 01134 break; 01135 case NodeType_ExpressionStatement: 01136 break; 01137 } 01138 } 01139 01140 void CppCodeCompletion::computeContext( SimpleContext*& ctx, StatementListAST* ast, int line, int col ) 01141 { 01142 int startLine, startColumn; 01143 int endLine, endColumn; 01144 ast->getStartPosition( &startLine, &startColumn ); 01145 ast->getEndPosition( &endLine, &endColumn ); 01146 01147 if( line > endLine || (line == endLine && endColumn < col) ) 01148 return; 01149 01150 QPtrList<StatementAST> l( ast->statementList() ); 01151 QPtrListIterator<StatementAST> it( l ); 01152 while( it.current() ){ 01153 StatementAST* stmt = it.current(); 01154 ++it; 01155 01156 computeContext( ctx, stmt, line, col ); 01157 } 01158 } 01159 01160 void CppCodeCompletion::computeContext( SimpleContext*& ctx, IfStatementAST* ast, int line, int col ) 01161 { 01162 computeContext( ctx, ast->statement(), line, col ); 01163 computeContext( ctx, ast->elseStatement(), line, col ); 01164 } 01165 01166 void CppCodeCompletion::computeContext( SimpleContext*& ctx, ForStatementAST* ast, int line, int col ) 01167 { 01168 computeContext( ctx, ast->condition(), line, col ); 01169 computeContext( ctx, ast->statement(), line, col ); 01170 } 01171 01172 void CppCodeCompletion::computeContext( SimpleContext*& ctx, DoStatementAST* ast, int line, int col ) 01173 { 01174 //computeContext( ctx, ast->condition(), line, col ); 01175 computeContext( ctx, ast->statement(), line, col ); 01176 } 01177 01178 void CppCodeCompletion::computeContext( SimpleContext*& ctx, WhileStatementAST* ast, int line, int col ) 01179 { 01180 computeContext( ctx, ast->condition(), line, col ); 01181 computeContext( ctx, ast->statement(), line, col ); 01182 } 01183 01184 void CppCodeCompletion::computeContext( SimpleContext*& ctx, SwitchStatementAST* ast, int line, int col ) 01185 { 01186 computeContext( ctx, ast->condition(), line, col ); 01187 computeContext( ctx, ast->statement(), line, col ); 01188 } 01189 01190 void CppCodeCompletion::computeContext( SimpleContext*& ctx, DeclarationStatementAST* ast, int line, int col ) 01191 { 01192 if( !ast->declaration() || ast->declaration()->nodeType() != NodeType_SimpleDeclaration ) 01193 return; 01194 01195 int startLine, startColumn; 01196 int endLine, endColumn; 01197 ast->getStartPosition( &startLine, &startColumn ); 01198 ast->getEndPosition( &endLine, &endColumn ); 01199 01200 if( line < startLine || (line == startLine && col <= startColumn) ) 01201 return; 01202 01203 SimpleDeclarationAST* simpleDecl = static_cast<SimpleDeclarationAST*>( ast->declaration() ); 01204 TypeSpecifierAST* typeSpec = simpleDecl->typeSpec(); 01205 QStringList type = typeName( typeSpec->text() ); 01206 01207 InitDeclaratorListAST* initDeclListAST = simpleDecl->initDeclaratorList(); 01208 if( !initDeclListAST ) 01209 return; 01210 01211 QPtrList<InitDeclaratorAST> l = initDeclListAST->initDeclaratorList(); 01212 QPtrListIterator<InitDeclaratorAST> it( l ); 01213 while( it.current() ){ 01214 DeclaratorAST* d = it.current()->declarator(); 01215 ++it; 01216 01217 if( d->declaratorId() ){ 01218 SimpleVariable var; 01219 var.type = type; 01220 var.name = toSimpleName( d->declaratorId() ); 01221 ctx->add( var ); 01222 //kdDebug(9007) << "add variable " << var.name << " with type " << var.type << endl; 01223 } 01224 } 01225 } 01226 01227 void CppCodeCompletion::computeContext( SimpleContext*& ctx, ConditionAST* ast, int line, int col ) 01228 { 01229 if( !ast->typeSpec() || !ast->declarator() || !ast->declarator()->declaratorId() ) 01230 return; 01231 01232 int startLine, startColumn; 01233 int endLine, endColumn; 01234 ast->getStartPosition( &startLine, &startColumn ); 01235 ast->getEndPosition( &endLine, &endColumn ); 01236 01237 if( line < startLine || (line == startLine && col <= startColumn) ) 01238 return; 01239 01240 QStringList type = typeName( ast->typeSpec()->text() ); 01241 SimpleVariable var; 01242 var.type = type; 01243 var.name = toSimpleName( ast->declarator()->declaratorId() ); 01244 ctx->add( var ); 01245 } 01246 01247 FunctionDefinitionAST * CppCodeCompletion::functionDefinition( AST* node ) 01248 { 01249 while( node ){ 01250 if( node->nodeType() == NodeType_FunctionDefinition ) 01251 return static_cast<FunctionDefinitionAST*>( node ); 01252 node = node->parent(); 01253 } 01254 return 0; 01255 } 01256 01257 QString CppCodeCompletion::getText( int startLine, int startColumn, int endLine, int endColumn ) 01258 { 01259 if( startLine == endLine ){ 01260 QString textLine = m_activeEditor->textLine( startLine ); 01261 return textLine.mid( startColumn, endColumn-startColumn ); 01262 } 01263 01264 QStringList contents; 01265 01266 for( int line=startLine; line<=endLine; ++line ){ 01267 QString textLine = m_activeEditor->textLine( line ); 01268 01269 if( line == startLine ) 01270 textLine = textLine.mid( startColumn ); 01271 if( line == endLine ) 01272 textLine = textLine.left( endColumn ); 01273 01274 contents << textLine; 01275 } 01276 return contents.join( "\n" ); 01277 } 01278 01279 // namespace? 01280 class ComputeRecoveryPoints: public TreeParser 01281 { 01282 public: 01283 ComputeRecoveryPoints( QPtrList<RecoveryPoint>& points ) 01284 : recoveryPoints( points ) 01285 { 01286 } 01287 01288 virtual void parseTranslationUnit( TranslationUnitAST* ast ) 01289 { 01290 QValueList<QStringList> dummy; 01291 01292 m_imports.push( dummy ); 01293 TreeParser::parseTranslationUnit( ast ); 01294 m_imports.pop(); 01295 01296 kdDebug(9007) << "found " << recoveryPoints.count() << " recovery points" << endl; 01297 } 01298 01299 virtual void parseUsingDirective( UsingDirectiveAST* ast ) 01300 { 01301 if( !ast->name() ) 01302 return; 01303 01304 QStringList type = CppCodeCompletion::typeName( ast->name()->text() ); 01305 m_imports.top().push_back( type ); 01306 } 01307 01308 virtual void parseNamespace( NamespaceAST* ast ) 01309 { 01310 //insertRecoveryPoint( ast ); 01311 m_currentScope.push_back( ast->namespaceName()->text() ); 01312 01313 m_imports.push( m_imports.top() ); // dup 01314 m_imports.top().push_back( m_currentScope ); 01315 01316 TreeParser::parseNamespace( ast ); 01317 01318 m_imports.pop(); 01319 m_currentScope.pop_back(); 01320 } 01321 01322 virtual void parseSimpleDeclaration( SimpleDeclarationAST* ast ) 01323 { 01324 TypeSpecifierAST* typeSpec = ast->typeSpec(); 01325 //InitDeclaratorListAST* declarators = ast->initDeclaratorList(); 01326 01327 if( typeSpec ) 01328 parseTypeSpecifier( typeSpec ); 01329 01330 //insertRecoveryPoint( ast ); 01331 TreeParser::parseSimpleDeclaration( ast ); 01332 } 01333 01334 virtual void parseFunctionDefinition( FunctionDefinitionAST* ast ) 01335 { 01336 m_imports.push( m_imports.top() ); // dup 01337 insertRecoveryPoint( ast ); 01338 m_imports.pop(); 01339 } 01340 01341 virtual void parseClassSpecifier( ClassSpecifierAST* ast ) 01342 { 01343 //insertRecoveryPoint( ast ); 01344 m_currentScope.push_back( toSimpleName(ast->name()) ); 01345 TreeParser::parseClassSpecifier( ast ); 01346 m_currentScope.pop_back(); 01347 } 01348 01349 void insertRecoveryPoint( AST* ast ) 01350 { 01351 if( !ast ) 01352 return; 01353 01354 RecoveryPoint* pt = new RecoveryPoint(); 01355 pt->kind = ast->nodeType(); 01356 pt->scope = m_currentScope; 01357 ast->getStartPosition( &pt->startLine, &pt->startColumn ); 01358 ast->getEndPosition( &pt->endLine, &pt->endColumn ); 01359 pt->imports = m_imports.top(); 01360 01361 recoveryPoints.append( pt ); 01362 } 01363 01364 private: 01365 QPtrList<RecoveryPoint>& recoveryPoints; 01366 QValueStack< QValueList<QStringList> > m_imports; 01367 QStringList m_currentScope; 01368 }; 01369 01370 01371 void CppCodeCompletion::computeRecoveryPoints( ) 01372 { 01373 kdDebug(9007) << "CppCodeCompletion::computeRecoveryPoints" << endl; 01374 01375 d->recoveryPoints.clear(); 01376 TranslationUnitAST* unit = m_pSupport->backgroundParser()->translationUnit( m_activeFileName ); 01377 if( !unit ) 01378 return; 01379 01380 ComputeRecoveryPoints walker( d->recoveryPoints ); 01381 walker.parseTranslationUnit( unit ); 01382 } 01383 01384 QStringList CppCodeCompletion::typeOf( const QValueList< Tag > & tags ) 01385 { 01386 QValueList<Tag>::ConstIterator it = tags.begin(); 01387 while( it != tags.end() ){ 01388 const Tag& tag = *it; 01389 ++it; 01390 01391 if( tag.hasAttribute("t") ) 01392 return typeName( tag.attribute("t").toString() ); 01393 else if( tag.kind() == Tag::Kind_Class || tag.kind() == Tag::Kind_Namespace ){ 01394 QStringList l = tag.scope(); 01395 l += typeName( tag.name() ); 01396 return l; 01397 } 01398 } 01399 01400 return QStringList(); 01401 } 01402 01403 QStringList CppCodeCompletion::typeOf( const QString & name, ClassDom klass ) 01404 { 01405 QStringList type; 01406 01407 if( klass->hasVariable(name) ) 01408 return typeName( klass->variableByName(name)->type() ); 01409 01410 type = typeOf( name, klass->functionList() ); 01411 if( !type.isEmpty() ) 01412 return type; 01413 01414 QStringList parents = klass->baseClassList(); 01415 for( QStringList::Iterator it=parents.begin(); it!=parents.end(); ++it ){ 01416 type = typeOf( name, typeName(*it) ); 01417 if( !type.isEmpty() ) 01418 return type; 01419 } 01420 01421 return QStringList(); 01422 } 01423 01424 QStringList CppCodeCompletion::typeOf( const QString & name, NamespaceDom scope ) 01425 { 01426 if( scope->hasVariable(name) ) 01427 return typeName( scope->variableByName(name)->type() ); 01428 01429 QStringList type; 01430 01431 type = typeOf( name, scope->functionList() ); 01432 if( !type.isEmpty() ) 01433 return type; 01434 01435 return QStringList(); 01436 } 01437 01438 QStringList CppCodeCompletion::typeOf( const QString & name, const FunctionList & methods ) 01439 { 01440 FunctionList::ConstIterator it = methods.begin(); 01441 while( it != methods.end() ){ 01442 FunctionDom meth = *it; 01443 ++it; 01444 01445 if( meth->name() == name ) 01446 return typeName( meth->resultType() ); 01447 } 01448 01449 return QStringList(); 01450 } 01451 01452 void CppCodeCompletion::computeCompletionEntryList( QValueList< KTextEditor::CompletionEntry > & entryList, const QStringList & type, bool isInstance ) 01453 { 01454 CppCodeCompletionConfig* cfg = m_pSupport->codeCompletionConfig(); 01455 QString key = findClass( type.join( "::" ) ); 01456 ClassDom klass = findContainer( key ); 01457 if( klass ){ 01458 computeCompletionEntryList( entryList, klass, isInstance ); 01459 } /*else*/ { 01460 QValueList<Catalog::QueryArgument> args; 01461 QValueList<Tag> tags; 01462 01463 args.clear(); 01464 args << Catalog::QueryArgument( "kind", Tag::Kind_FunctionDeclaration ) 01465 << Catalog::QueryArgument( "scope", type ); 01466 tags = m_repository->query( args ); 01467 computeCompletionEntryList( entryList, tags, isInstance ); 01468 01469 args.clear(); 01470 args << Catalog::QueryArgument( "kind", Tag::Kind_Variable ) 01471 << Catalog::QueryArgument( "scope", type ); 01472 tags = m_repository->query( args ); 01473 computeCompletionEntryList( entryList, tags, isInstance ); 01474 01475 if( !isInstance && cfg->includeEnums() ){ 01476 args.clear(); 01477 args << Catalog::QueryArgument( "kind", Tag::Kind_Enumerator ) 01478 << Catalog::QueryArgument( "scope", type ); 01479 tags = m_repository->query( args ); 01480 computeCompletionEntryList( entryList, tags, isInstance ); 01481 } 01482 01483 if( !isInstance && cfg->includeTypedefs() ){ 01484 args.clear(); 01485 args << Catalog::QueryArgument( "kind", Tag::Kind_Typedef ) 01486 << Catalog::QueryArgument( "scope", type ); 01487 tags = m_repository->query( args ); 01488 computeCompletionEntryList( entryList, tags, isInstance ); 01489 } 01490 01491 args.clear(); 01492 args << Catalog::QueryArgument( "kind", Tag::Kind_Base_class ); 01493 QString fullname = type.join( "::" ); 01494 /* if( fullname.length() >=2 ) 01495 args << Catalog::QueryArgument( "prefix", fullname.left(2) );*/ 01496 args << Catalog::QueryArgument( "name", fullname ); 01497 01498 QValueList<Tag> parents = m_repository->query( args ); 01499 QValueList<Tag>::Iterator it = parents.begin(); 01500 while( it != parents.end() ){ 01501 CppBaseClass<Tag> info( *it ); 01502 ++it; 01503 01504 computeCompletionEntryList( entryList, typeName(info.baseClass()), isInstance ); 01505 } 01506 } 01507 } 01508 01509 void CppCodeCompletion::computeCompletionEntryList( QValueList< KTextEditor::CompletionEntry > & entryList, QValueList< Tag > & tags, bool /*isInstance*/ ) 01510 { 01511 QValueList<Tag>::Iterator it = tags.begin(); 01512 while( it != tags.end() ){ 01513 Tag& tag = *it; 01514 ++it; 01515 01516 if( tag.name().isEmpty() ){ 01517 continue; 01518 } else if( m_completionMode != NormalCompletion ){ 01519 if( tag.kind() != Tag::Kind_FunctionDeclaration ) 01520 continue; 01521 01522 CppFunction<Tag> info( tag ); 01523 01524 if( m_completionMode == SlotCompletion && !info.isSlot() ) 01525 continue; 01526 else if( m_completionMode == SignalCompletion && !info.isSignal() ) 01527 continue; 01528 } 01529 01530 entryList << CodeInformationRepository::toEntry( tag, m_completionMode ); 01531 } 01532 } 01533 01534 void CppCodeCompletion::computeCompletionEntryList( QValueList< KTextEditor::CompletionEntry > & entryList, ClassDom klass, bool isInstance ) 01535 { 01536 computeCompletionEntryList( entryList, klass->functionList(), isInstance ); 01537 if( m_completionMode == NormalCompletion ) 01538 computeCompletionEntryList( entryList, klass->variableList(), isInstance ); 01539 01540 QStringList parents = klass->baseClassList(); 01541 for( QStringList::Iterator it=parents.begin(); it!=parents.end(); ++it ){ 01542 QStringList type = typeName( *it ); 01543 01544 if( !type.isEmpty() ) 01545 computeCompletionEntryList( entryList, type, isInstance ); 01546 } 01547 } 01548 01549 void CppCodeCompletion::computeCompletionEntryList( QValueList< KTextEditor::CompletionEntry > & entryList, NamespaceDom scope, bool isInstance ) 01550 { 01551 CppCodeCompletionConfig* cfg = m_pSupport->codeCompletionConfig(); 01552 01553 if( cfg->includeGlobalFunctions() ){ 01554 computeCompletionEntryList( entryList, scope->functionList(), isInstance ); 01555 01556 if( m_completionMode == NormalCompletion ) 01557 computeCompletionEntryList( entryList, scope->variableList(), isInstance ); 01558 } 01559 01560 if( !isInstance && cfg->includeTypes() ){ 01561 computeCompletionEntryList( entryList, scope->classList(), isInstance ); 01562 computeCompletionEntryList( entryList, scope->namespaceList(), isInstance ); 01563 } 01564 } 01565 01566 void CppCodeCompletion::computeCompletionEntryList( QValueList< KTextEditor::CompletionEntry > & entryList, const ClassList & lst, bool isInstance ) 01567 { 01568 CppCodeCompletionConfig* cfg = m_pSupport->codeCompletionConfig(); 01569 01570 ClassList::ConstIterator it = lst.begin(); 01571 while( it != lst.end() ){ 01572 ClassDom klass = *it; 01573 ++it; 01574 01575 KTextEditor::CompletionEntry entry; 01576 entry.prefix = "class"; 01577 entry.text = klass->name(); 01578 entryList << entry; 01579 01580 if( cfg->includeTypes() ){ 01581 computeCompletionEntryList( entryList, klass->classList(), isInstance ); 01582 } 01583 } 01584 } 01585 01586 void CppCodeCompletion::computeCompletionEntryList( QValueList< KTextEditor::CompletionEntry > & entryList, const NamespaceList & lst, bool /*isInstance*/ ) 01587 { 01588 NamespaceList::ConstIterator it = lst.begin(); 01589 while( it != lst.end() ){ 01590 NamespaceDom scope = *it; 01591 ++it; 01592 01593 KTextEditor::CompletionEntry entry; 01594 entry.prefix = "namespace"; 01595 entry.text = scope->name(); 01596 entryList << entry; 01597 } 01598 } 01599 01600 void CppCodeCompletion::computeCompletionEntryList( QValueList< KTextEditor::CompletionEntry > & entryList, const FunctionList & methods, bool isInstance ) 01601 { 01602 FunctionList::ConstIterator it = methods.begin(); 01603 while( it != methods.end() ){ 01604 FunctionDom meth = *it; 01605 ++it; 01606 01607 if( isInstance && meth->isStatic() ) 01608 continue; 01609 else if( m_completionMode == SignalCompletion && !meth->isSignal() ) 01610 continue; 01611 else if( m_completionMode == SlotCompletion && !meth->isSlot() ) 01612 continue; 01613 01614 KTextEditor::CompletionEntry entry; 01615 //entry.prefix = meth->type(); 01616 01617 entry.text = meth->name() + "("; 01618 01619 QString text; 01620 01621 ArgumentList args = meth->argumentList(); 01622 ArgumentList::Iterator argIt = args.begin(); 01623 while( argIt != args.end() ){ 01624 ArgumentDom arg = *argIt; 01625 ++argIt; 01626 01627 text += arg->type(); 01628 if( m_completionMode == NormalCompletion ) 01629 text += QString(" ") + arg->name(); 01630 01631 if( argIt != args.end() ) 01632 text += ", "; 01633 } 01634 01635 if( text.isEmpty() ) 01636 entry.text += ")"; 01637 else 01638 text += " )"; 01639 01640 if( meth->isConstant() ) 01641 text += " const"; 01642 01643 if( m_completionMode != NormalCompletion ) 01644 entry.text += text.stripWhiteSpace(); 01645 else 01646 entry.postfix = text; 01647 01648 entryList << entry; 01649 } 01650 } 01651 01652 void CppCodeCompletion::computeCompletionEntryList( QValueList< KTextEditor::CompletionEntry > & entryList, const VariableList & attributes, bool isInstance ) 01653 { 01654 if( m_completionMode != NormalCompletion ) 01655 return; 01656 01657 VariableList::ConstIterator it = attributes.begin(); 01658 while( it != attributes.end() ){ 01659 VariableDom attr = *it; 01660 ++it; 01661 01662 if( isInstance && attr->isStatic() ) 01663 continue; 01664 01665 KTextEditor::CompletionEntry entry; 01666 entry.text = attr->name(); 01667 entryList << entry; 01668 } 01669 } 01670 01671 void CppCodeCompletion::computeCompletionEntryList( QValueList< KTextEditor::CompletionEntry > & entryList, SimpleContext * ctx, bool /*isInstance*/ ) 01672 { 01673 while( ctx ){ 01674 QValueList<SimpleVariable> vars = ctx->vars(); 01675 QValueList<SimpleVariable>::ConstIterator it = vars.begin(); 01676 while( it != vars.end() ){ 01677 const SimpleVariable& var = *it; 01678 ++it; 01679 01680 KTextEditor::CompletionEntry entry; 01681 entry.text = var.name; 01682 entryList << entry; 01683 } 01684 ctx = ctx->prev(); 01685 } 01686 } 01687 01688 void CppCodeCompletion::computeSignatureList( QStringList & signatureList, const QString & name, const QStringList & scope ) 01689 { 01690 QString key = findClass( scope.join( "::" ) ); 01691 ClassDom klass = findContainer( key ); 01692 if( klass ){ 01693 computeSignatureList( signatureList, name, klass ); 01694 return; 01695 } 01696 01697 QValueList<Catalog::QueryArgument> args; 01698 args << Catalog::QueryArgument( "kind", Tag::Kind_FunctionDeclaration ); 01699 args << Catalog::QueryArgument( "scope", scope ); 01700 /* if( name.length() >=2 ) 01701 args << Catalog::QueryArgument( "prefix", name.left(2) ); */ 01702 args << Catalog::QueryArgument( "name", name ); 01703 01704 QValueList<Tag> tags = m_repository->query( args ); 01705 computeSignatureList( signatureList, name, tags ); 01706 01707 args.clear(); 01708 args << Catalog::QueryArgument( "kind", Tag::Kind_Base_class ); 01709 QString fullname = scope.join( "::" ); 01710 /* if( fullname.length() >=2 ) 01711 args << Catalog::QueryArgument( "prefix", fullname.left(2) );*/ 01712 01713 args << Catalog::QueryArgument( "name", fullname ); 01714 01715 QValueList<Tag> parents = m_repository->query( args ); 01716 QValueList<Tag>::Iterator it = parents.begin(); 01717 while( it != parents.end() ){ 01718 CppBaseClass<Tag> info( *it ); 01719 ++it; 01720 01721 computeSignatureList( signatureList, name, typeName(info.baseClass()) ); 01722 } 01723 } 01724 01725 void CppCodeCompletion::computeSignatureList( QStringList & signatureList, const QString & name, ClassDom klass ) 01726 { 01727 computeSignatureList( signatureList, name, klass->functionList() ); 01728 01729 QStringList parents = klass->baseClassList(); 01730 for( QStringList::Iterator it = parents.begin(); it!=parents.end(); ++it ){ 01731 QStringList type = typeName( *it ); 01732 if( !type.isEmpty() ) 01733 computeSignatureList( signatureList, name, type ); 01734 } 01735 } 01736 01737 void CppCodeCompletion::computeSignatureList( QStringList & signatureList, const QString & name, const FunctionList & methods ) 01738 { 01739 FunctionList::ConstIterator it = methods.begin(); 01740 while( it != methods.end() ){ 01741 FunctionDom meth = *it; 01742 ++it; 01743 01744 if( meth->name() != name ) 01745 continue; 01746 01747 QString signature; 01748 signature += meth->resultType() + " "; 01749 signature += meth->name() + "("; 01750 01751 ArgumentList args = meth->argumentList(); 01752 ArgumentList::Iterator argIt = args.begin(); 01753 while( argIt != args.end() ){ 01754 ArgumentDom arg = *argIt; 01755 ++argIt; 01756 01757 signature += arg->type() + " " + arg->name(); 01758 signature = signature.stripWhiteSpace(); 01759 01760 if( argIt != args.end() ) 01761 signature += ", "; 01762 } 01763 01764 signature += ")"; 01765 01766 if( meth->isConstant() ) 01767 signature += " const"; 01768 01769 signatureList << signature.stripWhiteSpace(); 01770 } 01771 } 01772 01773 void CppCodeCompletion::computeSignatureList( QStringList & signatureList, const QString & name, QValueList< Tag > & tags ) 01774 { 01775 QValueList<Tag>::Iterator it = tags.begin(); 01776 while( it != tags.end() ){ 01777 Tag& tag = *it; 01778 ++it; 01779 01780 CppFunction<Tag> info( tag ); 01781 if( info.name() != name ) 01782 continue; 01783 01784 QString signature; 01785 signature += info.type() + " " + tag.name() + "("; 01786 signature = signature.stripWhiteSpace(); 01787 01788 QStringList arguments = info.arguments(); 01789 QStringList argumentNames = info.argumentNames(); 01790 01791 for( uint i=0; i<arguments.size(); ++i ){ 01792 signature += arguments[ i ]; 01793 if( m_completionMode == NormalCompletion ){ 01794 QString argName = argumentNames[ i ]; 01795 if( !argName.isEmpty() ) 01796 signature += QString::fromLatin1( " " ) + argName; 01797 01798 if( i != (arguments.size()-1) ){ 01799 signature += ", "; 01800 } 01801 } 01802 } 01803 signature += ")"; 01804 01805 if( info.isConst() ) 01806 signature += " const"; 01807 01808 signatureList << signature.stripWhiteSpace(); 01809 } 01810 } 01811 01812 QString CppCodeCompletion::findClass( const QString & className ) 01813 { 01814 if( className.isEmpty() ) 01815 return className; 01816 01817 QStringList lst = d->classNameList.grep( QRegExp("\\b" + className + "$") ); 01818 if( lst.size() ){ 01819 kdDebug(9007) << "found class: " << lst[ 0 ] << endl; 01820 return lst[ 0 ]; 01821 } 01822 01823 return className; 01824 } 01825 01826 ClassDom CppCodeCompletion::findContainer( const QString& name, NamespaceDom container, bool includeImports ) 01827 { 01828 kdDebug(9007) << "-----------> findContainer name: " << name << " " << (container ? container->name() : QString("")) << endl; 01829 01830 if( name.isEmpty() ) 01831 return model_cast<ClassDom>( container ); 01832 01833 if( !container ) 01834 return findContainer( name, m_pSupport->codeModel()->globalNamespace(), includeImports ); 01835 01836 QStringList path = QStringList::split( "::", name ); 01837 QStringList::Iterator it = path.begin(); 01838 while( it != path.end() ){ 01839 QString s = *it; 01840 QStringList::Iterator sv_it = it; 01841 ++it; 01842 01843 kdDebug(9007) << "has namespace " << s << ": " << container->hasNamespace( s ) << endl; 01844 if( !container->hasNamespace(s) ) 01845 break; 01846 01847 NamespaceDom scope = container->namespaceByName( s ); 01848 01849 path.remove( sv_it ); 01850 container = scope; 01851 } 01852 01853 if( path.size() == 0 ) 01854 return model_cast<ClassDom>( container ); 01855 01856 QString className = path.join( "::" ); 01857 kdDebug(9007) << "find class: " << className << " in namespace " << container->name() << endl; 01858 01859 ClassDom c = model_cast<ClassDom>( container ); 01860 while( c && path.size() ){ 01861 QString s = path.front(); 01862 path.pop_front(); 01863 01864 if( !c->hasClass(s) ){ 01865 c = 0; 01866 break; 01867 } 01868 01869 ClassList classList = c->classByName( s ); 01870 c = classList[ 0 ]; 01871 for( ClassList::Iterator cit=classList.begin(); cit!=classList.end(); ++cit ){ 01872 if( QFileInfo( (*cit)->fileName() ).dirPath(true) == QFileInfo( m_activeFileName ).dirPath(true) ) 01873 c = *cit; 01874 } 01875 } 01876 01877 kdDebug(9007) << "found class: " << (c ? c->name() : QString("<anon>")) << endl; 01878 01879 #if 0 01880 if( !c && includeImports ){ 01881 01882 QStringList imports; 01883 QValueList<QStringList>::Iterator lIt = m_imports.begin(); 01884 while( lIt != m_imports.end() ){ 01885 imports += (*lIt ); 01886 ++lIt; 01887 } 01888 01889 QStringList::Iterator impIt = imports.begin(); 01890 while( impIt != imports.end() ){ 01891 ClassDom kl = findContainer( (*impIt) + "::" + name, container, false ); 01892 if( kl ) 01893 return kl; 01894 ++impIt; 01895 } 01896 } 01897 #endif 01898 01899 return c; 01900 } 01901 01902 void CppCodeCompletion::computeFileEntryList( ) 01903 { 01904 m_fileEntryList.clear(); 01905 01906 QStringList fileList = m_pSupport->project()->allFiles(); 01907 for( QStringList::Iterator it=fileList.begin(); it!=fileList.end(); ++it ) 01908 { 01909 if( !m_pSupport->isHeader(*it) ) 01910 continue; 01911 01912 KTextEditor::CompletionEntry entry; 01913 entry.text = QFileInfo( *it ).fileName(); 01914 m_fileEntryList.push_back( entry ); 01915 } 01916 01917 m_fileEntryList = unique( m_fileEntryList ); 01918 } 01919 01920 #include "cppcodecompletion.moc"
KDE Logo
This file is part of the documentation for KDevelop Version 3.0.4.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Oct 19 08:01:42 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003