00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
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; 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
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
00583
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
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
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
00724
00725
00726 Driver d;
00727 Lexer lexer( &d );
00729
00730 lexer.setSource( textToReparse );
00731 Parser parser( &d, &lexer );
00732
00733 parser.parseDeclaration( recoveredDecl );
00734
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
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
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
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
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 qHeapSort( entryList );
00938
00939 m_activeCompletion->showCompletionBox( entryList, word.length() );
00940 }
00941 } else {
00942 QStringList signatureList;
00943
00944 if( type.isEmpty() && expr.isEmpty() ){
00945 computeSignatureList( signatureList, word, m_pSupport->codeModel()->globalNamespace()->functionList() );
00946 computeSignatureList( signatureList, word, QStringList() );
00947
00948 if( !word.isEmpty() ){
00949 QStringList fakeType;
00950 fakeType << word;
00951 computeSignatureList( signatureList, word, fakeType );
00952 }
00953 } else if( !type.isEmpty() ){
00954 computeSignatureList( signatureList, word, type );
00955 }
00956
00957 if( !this_type.isEmpty() && expr.isEmpty() )
00958 computeSignatureList( signatureList, word, this_type );
00959
00960 if( !signatureList.isEmpty() ){
00961 signatureList = unique( signatureList );
00962 qHeapSort( signatureList );
00963 m_activeCompletion->showArgHint( signatureList, "()", "," );
00964 }
00965 }
00966
00967 delete( ctx );
00968 ctx = 0;
00969 }
00970
00971 void CppCodeCompletion::slotFileParsed( const QString& fileName )
00972 {
00973 if( fileName != m_activeFileName || !m_pSupport || !m_activeEditor )
00974 return;
00975
00976 m_pSupport->backgroundParser()->lock();
00977 computeRecoveryPoints();
00978 m_pSupport->backgroundParser()->unlock();
00979 }
00980
00981 QStringList CppCodeCompletion::typeOf( const QString& name, const QStringList& scope )
00982 {
00983 QStringList type;
00984
00985 if( name.isEmpty() )
00986 return type;
00987
00988 QString key = findClass( scope.join( "::" ) );
00989 ClassDom klass = findContainer( key );
00990 if( klass ){
00991 return typeOf( name, klass );
00992 } else {
00993 type = typeOf( name, m_pSupport->codeModel()->globalNamespace() );
00994 if( !type.isEmpty() )
00995 return type;
00996 }
00997
00998 QValueList<Catalog::QueryArgument> args;
00999 QTime t;
01000
01001 t.start();
01002 args << Catalog::QueryArgument( "scope", scope );
01003
01004
01005 args << Catalog::QueryArgument( "name", name );
01006 QValueList<Tag> tags( m_repository->query(args) );
01007 kdDebug(9007) << "type of " << name << " in " << scope.join("::") << " takes " << t.elapsed() << endl;
01008 type = typeOf( tags );
01009
01010 if( type.isEmpty() ){
01011
01012 t.restart();
01013 QValueList<Tag> parents( m_repository->getBaseClassList( scope.join("::") ) );
01014 kdDebug(9007) << "get parents of " << scope.join("::") << " takes " << t.elapsed() << endl;
01015 QValueList<Tag>::Iterator it = parents.begin();
01016 while( it != parents.end() ){
01017 Tag& tag = *it;
01018 ++it;
01019
01020 CppBaseClass<Tag> info( tag );
01021
01022 QStringList newScope = typeName( info.baseClass() );
01023 type = typeOf( name, newScope );
01024 if( !type.isEmpty() )
01025 break;
01026 }
01027 }
01028
01029 return type;
01030 }
01031
01032 void CppCodeCompletion::setupCodeInformationRepository( )
01033 {
01034 }
01035
01036 QStringList CppCodeCompletion::typeName( const QString& str )
01037 {
01038 if( str.isEmpty() )
01039 return QStringList();
01040
01041 Driver d;
01042 Lexer lex( &d );
01043 lex.setSource( str );
01044 Parser parser( &d, &lex );
01045
01046 TypeSpecifierAST::Node typeSpec;
01047 if( parser.parseTypeSpecifier(typeSpec) ){
01048 NameAST* name = typeSpec->name();
01049
01050 QPtrList<ClassOrNamespaceNameAST> l = name->classOrNamespaceNameList();
01051 QPtrListIterator<ClassOrNamespaceNameAST> it( l );
01052
01053 QString type;
01054 while( it.current() ){
01055 if( it.current()->name() ){
01056 type += it.current()->name()->text() + "::";
01057 }
01058 ++it;
01059 }
01060
01061 if( name->unqualifiedName() && name->unqualifiedName()->name() ){
01062 type += name->unqualifiedName()->name()->text();
01063 }
01064
01065 return QStringList::split( "::", type );
01066 }
01067
01068 return QStringList();
01069 }
01070
01071 SimpleContext* CppCodeCompletion::computeContext( FunctionDefinitionAST * ast, int line, int col )
01072 {
01073 kdDebug(9007) << "CppCodeCompletion::computeContext() -- main" << endl;
01074
01075 SimpleContext* ctx = new SimpleContext();
01076
01077 if( ast && ast->initDeclarator() && ast->initDeclarator()->declarator() ){
01078 DeclaratorAST* d = ast->initDeclarator()->declarator();
01079 if( ParameterDeclarationClauseAST* clause = d->parameterDeclarationClause() ){
01080 if( ParameterDeclarationListAST* params = clause->parameterDeclarationList() ){
01081 QPtrList<ParameterDeclarationAST> l( params->parameterList() );
01082 QPtrListIterator<ParameterDeclarationAST> it( l );
01083 while( it.current() ){
01084 ParameterDeclarationAST* param = it.current();
01085 ++it;
01086
01087 SimpleVariable var;
01088 var.type = typeName( param->typeSpec()->text() );
01089 var.name = declaratorToString( param->declarator(), QString::null, true );
01090
01091 if( !var.type.isEmpty() ){
01092 ctx->add( var );
01093
01094 }
01095 }
01096 }
01097 }
01098 }
01099
01100 computeContext( ctx, ast->functionBody(), line, col );
01101 return ctx;
01102 }
01103
01104 void CppCodeCompletion::computeContext( SimpleContext*& ctx, StatementAST* stmt, int line, int col )
01105 {
01106 if( !stmt )
01107 return;
01108
01109 switch( stmt->nodeType() )
01110 {
01111 case NodeType_IfStatement:
01112 computeContext( ctx, static_cast<IfStatementAST*>(stmt), line, col );
01113 break;
01114 case NodeType_WhileStatement:
01115 computeContext( ctx, static_cast<WhileStatementAST*>(stmt), line, col );
01116 break;
01117 case NodeType_DoStatement:
01118 computeContext( ctx, static_cast<DoStatementAST*>(stmt), line, col );
01119 break;
01120 case NodeType_ForStatement:
01121 computeContext( ctx, static_cast<ForStatementAST*>(stmt), line, col );
01122 break;
01123 case NodeType_SwitchStatement:
01124 computeContext( ctx, static_cast<SwitchStatementAST*>(stmt), line, col );
01125 break;
01126 case NodeType_DeclarationStatement:
01127 computeContext( ctx, static_cast<DeclarationStatementAST*>(stmt), line, col );
01128 break;
01129 case NodeType_StatementList:
01130 computeContext( ctx, static_cast<StatementListAST*>(stmt), line, col );
01131 break;
01132 case NodeType_ExpressionStatement:
01133 break;
01134 }
01135 }
01136
01137 void CppCodeCompletion::computeContext( SimpleContext*& ctx, StatementListAST* ast, int line, int col )
01138 {
01139 int startLine, startColumn;
01140 int endLine, endColumn;
01141 ast->getStartPosition( &startLine, &startColumn );
01142 ast->getEndPosition( &endLine, &endColumn );
01143
01144 if( line > endLine || (line == endLine && endColumn < col) )
01145 return;
01146
01147 QPtrList<StatementAST> l( ast->statementList() );
01148 QPtrListIterator<StatementAST> it( l );
01149 while( it.current() ){
01150 StatementAST* stmt = it.current();
01151 ++it;
01152
01153 computeContext( ctx, stmt, line, col );
01154 }
01155 }
01156
01157 void CppCodeCompletion::computeContext( SimpleContext*& ctx, IfStatementAST* ast, int line, int col )
01158 {
01159 computeContext( ctx, ast->statement(), line, col );
01160 computeContext( ctx, ast->elseStatement(), line, col );
01161 }
01162
01163 void CppCodeCompletion::computeContext( SimpleContext*& ctx, ForStatementAST* ast, int line, int col )
01164 {
01165 computeContext( ctx, ast->condition(), line, col );
01166 computeContext( ctx, ast->statement(), line, col );
01167 }
01168
01169 void CppCodeCompletion::computeContext( SimpleContext*& ctx, DoStatementAST* ast, int line, int col )
01170 {
01171
01172 computeContext( ctx, ast->statement(), line, col );
01173 }
01174
01175 void CppCodeCompletion::computeContext( SimpleContext*& ctx, WhileStatementAST* ast, int line, int col )
01176 {
01177 computeContext( ctx, ast->condition(), line, col );
01178 computeContext( ctx, ast->statement(), line, col );
01179 }
01180
01181 void CppCodeCompletion::computeContext( SimpleContext*& ctx, SwitchStatementAST* ast, int line, int col )
01182 {
01183 computeContext( ctx, ast->condition(), line, col );
01184 computeContext( ctx, ast->statement(), line, col );
01185 }
01186
01187 void CppCodeCompletion::computeContext( SimpleContext*& ctx, DeclarationStatementAST* ast, int line, int col )
01188 {
01189 if( !ast->declaration() || ast->declaration()->nodeType() != NodeType_SimpleDeclaration )
01190 return;
01191
01192 int startLine, startColumn;
01193 int endLine, endColumn;
01194 ast->getStartPosition( &startLine, &startColumn );
01195 ast->getEndPosition( &endLine, &endColumn );
01196
01197 if( line < startLine || (line == startLine && col <= startColumn) )
01198 return;
01199
01200 SimpleDeclarationAST* simpleDecl = static_cast<SimpleDeclarationAST*>( ast->declaration() );
01201 TypeSpecifierAST* typeSpec = simpleDecl->typeSpec();
01202 QStringList type = typeName( typeSpec->text() );
01203
01204 InitDeclaratorListAST* initDeclListAST = simpleDecl->initDeclaratorList();
01205 if( !initDeclListAST )
01206 return;
01207
01208 QPtrList<InitDeclaratorAST> l = initDeclListAST->initDeclaratorList();
01209 QPtrListIterator<InitDeclaratorAST> it( l );
01210 while( it.current() ){
01211 DeclaratorAST* d = it.current()->declarator();
01212 ++it;
01213
01214 if( d->declaratorId() ){
01215 SimpleVariable var;
01216 var.type = type;
01217 var.name = toSimpleName( d->declaratorId() );
01218 ctx->add( var );
01219
01220 }
01221 }
01222 }
01223
01224 void CppCodeCompletion::computeContext( SimpleContext*& ctx, ConditionAST* ast, int line, int col )
01225 {
01226 if( !ast->typeSpec() || !ast->declarator() || !ast->declarator()->declaratorId() )
01227 return;
01228
01229 int startLine, startColumn;
01230 int endLine, endColumn;
01231 ast->getStartPosition( &startLine, &startColumn );
01232 ast->getEndPosition( &endLine, &endColumn );
01233
01234 if( line < startLine || (line == startLine && col <= startColumn) )
01235 return;
01236
01237 QStringList type = typeName( ast->typeSpec()->text() );
01238 SimpleVariable var;
01239 var.type = type;
01240 var.name = toSimpleName( ast->declarator()->declaratorId() );
01241 ctx->add( var );
01242 }
01243
01244 FunctionDefinitionAST * CppCodeCompletion::functionDefinition( AST* node )
01245 {
01246 while( node ){
01247 if( node->nodeType() == NodeType_FunctionDefinition )
01248 return static_cast<FunctionDefinitionAST*>( node );
01249 node = node->parent();
01250 }
01251 return 0;
01252 }
01253
01254 QString CppCodeCompletion::getText( int startLine, int startColumn, int endLine, int endColumn )
01255 {
01256 if( startLine == endLine ){
01257 QString textLine = m_activeEditor->textLine( startLine );
01258 return textLine.mid( startColumn, endColumn-startColumn );
01259 }
01260
01261 QStringList contents;
01262
01263 for( int line=startLine; line<=endLine; ++line ){
01264 QString textLine = m_activeEditor->textLine( line );
01265
01266 if( line == startLine )
01267 textLine = textLine.mid( startColumn );
01268 if( line == endLine )
01269 textLine = textLine.left( endColumn );
01270
01271 contents << textLine;
01272 }
01273 return contents.join( "\n" );
01274 }
01275
01276
01277 class ComputeRecoveryPoints: public TreeParser
01278 {
01279 public:
01280 ComputeRecoveryPoints( QPtrList<RecoveryPoint>& points )
01281 : recoveryPoints( points )
01282 {
01283 }
01284
01285 virtual void parseTranslationUnit( TranslationUnitAST* ast )
01286 {
01287 QValueList<QStringList> dummy;
01288
01289 m_imports.push( dummy );
01290 TreeParser::parseTranslationUnit( ast );
01291 m_imports.pop();
01292
01293 kdDebug(9007) << "found " << recoveryPoints.count() << " recovery points" << endl;
01294 }
01295
01296 virtual void parseUsingDirective( UsingDirectiveAST* ast )
01297 {
01298 if( !ast->name() )
01299 return;
01300
01301 QStringList type = CppCodeCompletion::typeName( ast->name()->text() );
01302 m_imports.top().push_back( type );
01303 }
01304
01305 virtual void parseNamespace( NamespaceAST* ast )
01306 {
01307
01308 m_currentScope.push_back( ast->namespaceName()->text() );
01309
01310 m_imports.push( m_imports.top() );
01311 m_imports.top().push_back( m_currentScope );
01312
01313 TreeParser::parseNamespace( ast );
01314
01315 m_imports.pop();
01316 m_currentScope.pop_back();
01317 }
01318
01319 virtual void parseSimpleDeclaration( SimpleDeclarationAST* ast )
01320 {
01321 TypeSpecifierAST* typeSpec = ast->typeSpec();
01322
01323
01324 if( typeSpec )
01325 parseTypeSpecifier( typeSpec );
01326
01327
01328 TreeParser::parseSimpleDeclaration( ast );
01329 }
01330
01331 virtual void parseFunctionDefinition( FunctionDefinitionAST* ast )
01332 {
01333 m_imports.push( m_imports.top() );
01334 insertRecoveryPoint( ast );
01335 m_imports.pop();
01336 }
01337
01338 virtual void parseClassSpecifier( ClassSpecifierAST* ast )
01339 {
01340
01341 m_currentScope.push_back( toSimpleName(ast->name()) );
01342 TreeParser::parseClassSpecifier( ast );
01343 m_currentScope.pop_back();
01344 }
01345
01346 void insertRecoveryPoint( AST* ast )
01347 {
01348 if( !ast )
01349 return;
01350
01351 RecoveryPoint* pt = new RecoveryPoint();
01352 pt->kind = ast->nodeType();
01353 pt->scope = m_currentScope;
01354 ast->getStartPosition( &pt->startLine, &pt->startColumn );
01355 ast->getEndPosition( &pt->endLine, &pt->endColumn );
01356 pt->imports = m_imports.top();
01357
01358 recoveryPoints.append( pt );
01359 }
01360
01361 private:
01362 QPtrList<RecoveryPoint>& recoveryPoints;
01363 QValueStack< QValueList<QStringList> > m_imports;
01364 QStringList m_currentScope;
01365 };
01366
01367
01368 void CppCodeCompletion::computeRecoveryPoints( )
01369 {
01370 kdDebug(9007) << "CppCodeCompletion::computeRecoveryPoints" << endl;
01371
01372 d->recoveryPoints.clear();
01373 TranslationUnitAST* unit = m_pSupport->backgroundParser()->translationUnit( m_activeFileName );
01374 if( !unit )
01375 return;
01376
01377 ComputeRecoveryPoints walker( d->recoveryPoints );
01378 walker.parseTranslationUnit( unit );
01379 }
01380
01381 QStringList CppCodeCompletion::typeOf( const QValueList< Tag > & tags )
01382 {
01383 QValueList<Tag>::ConstIterator it = tags.begin();
01384 while( it != tags.end() ){
01385 const Tag& tag = *it;
01386 ++it;
01387
01388 if( tag.hasAttribute("t") )
01389 return typeName( tag.attribute("t").toString() );
01390 else if( tag.kind() == Tag::Kind_Class || tag.kind() == Tag::Kind_Namespace ){
01391 QStringList l = tag.scope();
01392 l += typeName( tag.name() );
01393 return l;
01394 }
01395 }
01396
01397 return QStringList();
01398 }
01399
01400 QStringList CppCodeCompletion::typeOf( const QString & name, ClassDom klass )
01401 {
01402 QStringList type;
01403
01404 if( klass->hasVariable(name) )
01405 return typeName( klass->variableByName(name)->type() );
01406
01407 type = typeOf( name, klass->functionList() );
01408 if( !type.isEmpty() )
01409 return type;
01410
01411 QStringList parents = klass->baseClassList();
01412 for( QStringList::Iterator it=parents.begin(); it!=parents.end(); ++it ){
01413 type = typeOf( name, typeName(*it) );
01414 if( !type.isEmpty() )
01415 return type;
01416 }
01417
01418 return QStringList();
01419 }
01420
01421 QStringList CppCodeCompletion::typeOf( const QString & name, NamespaceDom scope )
01422 {
01423 if( scope->hasVariable(name) )
01424 return typeName( scope->variableByName(name)->type() );
01425
01426 QStringList type;
01427
01428 type = typeOf( name, scope->functionList() );
01429 if( !type.isEmpty() )
01430 return type;
01431
01432 return QStringList();
01433 }
01434
01435 QStringList CppCodeCompletion::typeOf( const QString & name, const FunctionList & methods )
01436 {
01437 FunctionList::ConstIterator it = methods.begin();
01438 while( it != methods.end() ){
01439 FunctionDom meth = *it;
01440 ++it;
01441
01442 if( meth->name() == name )
01443 return typeName( meth->resultType() );
01444 }
01445
01446 return QStringList();
01447 }
01448
01449 void CppCodeCompletion::computeCompletionEntryList( QValueList< KTextEditor::CompletionEntry > & entryList, const QStringList & type, bool isInstance )
01450 {
01451 CppCodeCompletionConfig* cfg = m_pSupport->codeCompletionConfig();
01452 QString key = findClass( type.join( "::" ) );
01453 ClassDom klass = findContainer( key );
01454 if( klass ){
01455 computeCompletionEntryList( entryList, klass, isInstance );
01456 } {
01457 QValueList<Catalog::QueryArgument> args;
01458 QValueList<Tag> tags;
01459
01460 args.clear();
01461 args << Catalog::QueryArgument( "kind", Tag::Kind_FunctionDeclaration )
01462 << Catalog::QueryArgument( "scope", type );
01463 tags = m_repository->query( args );
01464 computeCompletionEntryList( entryList, tags, isInstance );
01465
01466 args.clear();
01467 args << Catalog::QueryArgument( "kind", Tag::Kind_Variable )
01468 << Catalog::QueryArgument( "scope", type );
01469 tags = m_repository->query( args );
01470 computeCompletionEntryList( entryList, tags, isInstance );
01471
01472 if( !isInstance && cfg->includeEnums() ){
01473 args.clear();
01474 args << Catalog::QueryArgument( "kind", Tag::Kind_Enumerator )
01475 << Catalog::QueryArgument( "scope", type );
01476 tags = m_repository->query( args );
01477 computeCompletionEntryList( entryList, tags, isInstance );
01478 }
01479
01480 if( !isInstance && cfg->includeTypedefs() ){
01481 args.clear();
01482 args << Catalog::QueryArgument( "kind", Tag::Kind_Typedef )
01483 << Catalog::QueryArgument( "scope", type );
01484 tags = m_repository->query( args );
01485 computeCompletionEntryList( entryList, tags, isInstance );
01486 }
01487
01488 args.clear();
01489 args << Catalog::QueryArgument( "kind", Tag::Kind_Base_class );
01490 QString fullname = type.join( "::" );
01491
01492
01493 args << Catalog::QueryArgument( "name", fullname );
01494
01495 QValueList<Tag> parents = m_repository->query( args );
01496 QValueList<Tag>::Iterator it = parents.begin();
01497 while( it != parents.end() ){
01498 CppBaseClass<Tag> info( *it );
01499 ++it;
01500
01501 computeCompletionEntryList( entryList, typeName(info.baseClass()), isInstance );
01502 }
01503 }
01504 }
01505
01506 void CppCodeCompletion::computeCompletionEntryList( QValueList< KTextEditor::CompletionEntry > & entryList, QValueList< Tag > & tags, bool )
01507 {
01508 QValueList<Tag>::Iterator it = tags.begin();
01509 while( it != tags.end() ){
01510 Tag& tag = *it;
01511 ++it;
01512
01513 if( tag.name().isEmpty() ){
01514 continue;
01515 } else if( m_completionMode != NormalCompletion ){
01516 if( tag.kind() != Tag::Kind_FunctionDeclaration )
01517 continue;
01518
01519 CppFunction<Tag> info( tag );
01520
01521 if( m_completionMode == SlotCompletion && !info.isSlot() )
01522 continue;
01523 else if( m_completionMode == SignalCompletion && !info.isSignal() )
01524 continue;
01525 }
01526
01527 entryList << CodeInformationRepository::toEntry( tag, m_completionMode );
01528 }
01529 }
01530
01531 void CppCodeCompletion::computeCompletionEntryList( QValueList< KTextEditor::CompletionEntry > & entryList, ClassDom klass, bool isInstance )
01532 {
01533 computeCompletionEntryList( entryList, klass->functionList(), isInstance );
01534 if( m_completionMode == NormalCompletion )
01535 computeCompletionEntryList( entryList, klass->variableList(), isInstance );
01536
01537 QStringList parents = klass->baseClassList();
01538 for( QStringList::Iterator it=parents.begin(); it!=parents.end(); ++it ){
01539 QStringList type = typeName( *it );
01540
01541 if( !type.isEmpty() )
01542 computeCompletionEntryList( entryList, type, isInstance );
01543 }
01544 }
01545
01546 void CppCodeCompletion::computeCompletionEntryList( QValueList< KTextEditor::CompletionEntry > & entryList, NamespaceDom scope, bool isInstance )
01547 {
01548 CppCodeCompletionConfig* cfg = m_pSupport->codeCompletionConfig();
01549
01550 if( cfg->includeGlobalFunctions() ){
01551 computeCompletionEntryList( entryList, scope->functionList(), isInstance );
01552
01553 if( m_completionMode == NormalCompletion )
01554 computeCompletionEntryList( entryList, scope->variableList(), isInstance );
01555 }
01556
01557 if( !isInstance && cfg->includeTypes() ){
01558 computeCompletionEntryList( entryList, scope->classList(), isInstance );
01559 computeCompletionEntryList( entryList, scope->namespaceList(), isInstance );
01560 }
01561 }
01562
01563 void CppCodeCompletion::computeCompletionEntryList( QValueList< KTextEditor::CompletionEntry > & entryList, const ClassList & lst, bool isInstance )
01564 {
01565 CppCodeCompletionConfig* cfg = m_pSupport->codeCompletionConfig();
01566
01567 ClassList::ConstIterator it = lst.begin();
01568 while( it != lst.end() ){
01569 ClassDom klass = *it;
01570 ++it;
01571
01572 KTextEditor::CompletionEntry entry;
01573 entry.prefix = "class";
01574 entry.text = klass->name();
01575 entryList << entry;
01576
01577 if( cfg->includeTypes() ){
01578 computeCompletionEntryList( entryList, klass->classList(), isInstance );
01579 }
01580 }
01581 }
01582
01583 void CppCodeCompletion::computeCompletionEntryList( QValueList< KTextEditor::CompletionEntry > & entryList, const NamespaceList & lst, bool )
01584 {
01585 NamespaceList::ConstIterator it = lst.begin();
01586 while( it != lst.end() ){
01587 NamespaceDom scope = *it;
01588 ++it;
01589
01590 KTextEditor::CompletionEntry entry;
01591 entry.prefix = "namespace";
01592 entry.text = scope->name();
01593 entryList << entry;
01594 }
01595 }
01596
01597 void CppCodeCompletion::computeCompletionEntryList( QValueList< KTextEditor::CompletionEntry > & entryList, const FunctionList & methods, bool isInstance )
01598 {
01599 FunctionList::ConstIterator it = methods.begin();
01600 while( it != methods.end() ){
01601 FunctionDom meth = *it;
01602 ++it;
01603
01604 if( isInstance && meth->isStatic() )
01605 continue;
01606 else if( m_completionMode == SignalCompletion && !meth->isSignal() )
01607 continue;
01608 else if( m_completionMode == SlotCompletion && !meth->isSlot() )
01609 continue;
01610
01611 KTextEditor::CompletionEntry entry;
01612
01613
01614 entry.text = meth->name() + "(";
01615
01616 QString text;
01617
01618 ArgumentList args = meth->argumentList();
01619 ArgumentList::Iterator argIt = args.begin();
01620 while( argIt != args.end() ){
01621 ArgumentDom arg = *argIt;
01622 ++argIt;
01623
01624 text += arg->type();
01625 if( m_completionMode == NormalCompletion )
01626 text += QString(" ") + arg->name();
01627
01628 if( argIt != args.end() )
01629 text += ", ";
01630 }
01631
01632 if( text.isEmpty() )
01633 entry.text += ")";
01634 else
01635 text += " )";
01636
01637 if( meth->isConstant() )
01638 text += " const";
01639
01640 if( m_completionMode != NormalCompletion )
01641 entry.text += text.stripWhiteSpace();
01642 else
01643 entry.postfix = text;
01644
01645 entryList << entry;
01646 }
01647 }
01648
01649 void CppCodeCompletion::computeCompletionEntryList( QValueList< KTextEditor::CompletionEntry > & entryList, const VariableList & attributes, bool isInstance )
01650 {
01651 if( m_completionMode != NormalCompletion )
01652 return;
01653
01654 VariableList::ConstIterator it = attributes.begin();
01655 while( it != attributes.end() ){
01656 VariableDom attr = *it;
01657 ++it;
01658
01659 if( isInstance && attr->isStatic() )
01660 continue;
01661
01662 KTextEditor::CompletionEntry entry;
01663 entry.text = attr->name();
01664 entryList << entry;
01665 }
01666 }
01667
01668 void CppCodeCompletion::computeCompletionEntryList( QValueList< KTextEditor::CompletionEntry > & entryList, SimpleContext * ctx, bool )
01669 {
01670 while( ctx ){
01671 QValueList<SimpleVariable> vars = ctx->vars();
01672 QValueList<SimpleVariable>::ConstIterator it = vars.begin();
01673 while( it != vars.end() ){
01674 const SimpleVariable& var = *it;
01675 ++it;
01676
01677 KTextEditor::CompletionEntry entry;
01678 entry.text = var.name;
01679 entryList << entry;
01680 }
01681 ctx = ctx->prev();
01682 }
01683 }
01684
01685 void CppCodeCompletion::computeSignatureList( QStringList & signatureList, const QString & name, const QStringList & scope )
01686 {
01687 QString key = findClass( scope.join( "::" ) );
01688 ClassDom klass = findContainer( key );
01689 if( klass ){
01690 computeSignatureList( signatureList, name, klass );
01691 return;
01692 }
01693
01694 QValueList<Catalog::QueryArgument> args;
01695 args << Catalog::QueryArgument( "kind", Tag::Kind_FunctionDeclaration );
01696 args << Catalog::QueryArgument( "scope", scope );
01697
01698
01699 args << Catalog::QueryArgument( "name", name );
01700
01701 QValueList<Tag> tags = m_repository->query( args );
01702 computeSignatureList( signatureList, name, tags );
01703
01704 args.clear();
01705 args << Catalog::QueryArgument( "kind", Tag::Kind_Base_class );
01706 QString fullname = scope.join( "::" );
01707
01708
01709
01710 args << Catalog::QueryArgument( "name", fullname );
01711
01712 QValueList<Tag> parents = m_repository->query( args );
01713 QValueList<Tag>::Iterator it = parents.begin();
01714 while( it != parents.end() ){
01715 CppBaseClass<Tag> info( *it );
01716 ++it;
01717
01718 computeSignatureList( signatureList, name, typeName(info.baseClass()) );
01719 }
01720 }
01721
01722 void CppCodeCompletion::computeSignatureList( QStringList & signatureList, const QString & name, ClassDom klass )
01723 {
01724 computeSignatureList( signatureList, name, klass->functionList() );
01725
01726 QStringList parents = klass->baseClassList();
01727 for( QStringList::Iterator it = parents.begin(); it!=parents.end(); ++it ){
01728 QStringList type = typeName( *it );
01729 if( !type.isEmpty() )
01730 computeSignatureList( signatureList, name, type );
01731 }
01732 }
01733
01734 void CppCodeCompletion::computeSignatureList( QStringList & signatureList, const QString & name, const FunctionList & methods )
01735 {
01736 FunctionList::ConstIterator it = methods.begin();
01737 while( it != methods.end() ){
01738 FunctionDom meth = *it;
01739 ++it;
01740
01741 if( meth->name() != name )
01742 continue;
01743
01744 QString signature;
01745 signature += meth->resultType() + " ";
01746 signature += meth->name() + "(";
01747
01748 ArgumentList args = meth->argumentList();
01749 ArgumentList::Iterator argIt = args.begin();
01750 while( argIt != args.end() ){
01751 ArgumentDom arg = *argIt;
01752 ++argIt;
01753
01754 signature += arg->type() + " " + arg->name();
01755 signature = signature.stripWhiteSpace();
01756
01757 if( argIt != args.end() )
01758 signature += ", ";
01759 }
01760
01761 signature += ")";
01762
01763 if( meth->isConstant() )
01764 signature += " const";
01765
01766 signatureList << signature.stripWhiteSpace();
01767 }
01768 }
01769
01770 void CppCodeCompletion::computeSignatureList( QStringList & signatureList, const QString & name, QValueList< Tag > & tags )
01771 {
01772 QValueList<Tag>::Iterator it = tags.begin();
01773 while( it != tags.end() ){
01774 Tag& tag = *it;
01775 ++it;
01776
01777 CppFunction<Tag> info( tag );
01778 if( info.name() != name )
01779 continue;
01780
01781 QString signature;
01782 signature += info.type() + " " + tag.name() + "(";
01783 signature = signature.stripWhiteSpace();
01784
01785 QStringList arguments = info.arguments();
01786 QStringList argumentNames = info.argumentNames();
01787
01788 for( uint i=0; i<arguments.size(); ++i ){
01789 signature += arguments[ i ];
01790 if( m_completionMode == NormalCompletion ){
01791 QString argName = argumentNames[ i ];
01792 if( !argName.isEmpty() )
01793 signature += QString::fromLatin1( " " ) + argName;
01794
01795 if( i != (arguments.size()-1) ){
01796 signature += ", ";
01797 }
01798 }
01799 }
01800 signature += ")";
01801
01802 if( info.isConst() )
01803 signature += " const";
01804
01805 signatureList << signature.stripWhiteSpace();
01806 }
01807 }
01808
01809 QString CppCodeCompletion::findClass( const QString & className )
01810 {
01811 if( className.isEmpty() )
01812 return className;
01813
01814 QStringList lst = d->classNameList.grep( QRegExp("\\b" + className + "$") );
01815 if( lst.size() ){
01816 kdDebug(9007) << "found class: " << lst[ 0 ] << endl;
01817 return lst[ 0 ];
01818 }
01819
01820 return className;
01821 }
01822
01823 ClassDom CppCodeCompletion::findContainer( const QString& name, NamespaceDom container, bool includeImports )
01824 {
01825 kdDebug(9007) << "-----------> findContainer name: " << name << " " << (container ? container->name() : QString("")) << endl;
01826
01827 if( name.isEmpty() )
01828 return model_cast<ClassDom>( container );
01829
01830 if( !container )
01831 return findContainer( name, m_pSupport->codeModel()->globalNamespace(), includeImports );
01832
01833 QStringList path = QStringList::split( "::", name );
01834 QStringList::Iterator it = path.begin();
01835 while( it != path.end() ){
01836 QString s = *it;
01837 QStringList::Iterator sv_it = it;
01838 ++it;
01839
01840 kdDebug(9007) << "has namespace " << s << ": " << container->hasNamespace( s ) << endl;
01841 if( !container->hasNamespace(s) )
01842 break;
01843
01844 NamespaceDom scope = container->namespaceByName( s );
01845
01846 path.remove( sv_it );
01847 container = scope;
01848 }
01849
01850 if( path.size() == 0 )
01851 return model_cast<ClassDom>( container );
01852
01853 QString className = path.join( "::" );
01854 kdDebug(9007) << "find class: " << className << " in namespace " << container->name() << endl;
01855
01856 ClassDom c = model_cast<ClassDom>( container );
01857 while( c && path.size() ){
01858 QString s = path.front();
01859 path.pop_front();
01860
01861 if( !c->hasClass(s) ){
01862 c = 0;
01863 break;
01864 }
01865
01866 ClassList classList = c->classByName( s );
01867 c = classList[ 0 ];
01868 for( ClassList::Iterator cit=classList.begin(); cit!=classList.end(); ++cit ){
01869 if( QFileInfo( (*cit)->fileName() ).dirPath(true) == QFileInfo( m_activeFileName ).dirPath(true) )
01870 c = *cit;
01871 }
01872 }
01873
01874 kdDebug(9007) << "found class: " << (c ? c->name() : QString("<anon>")) << endl;
01875
01876 #if 0
01877 if( !c && includeImports ){
01878
01879 QStringList imports;
01880 QValueList<QStringList>::Iterator lIt = m_imports.begin();
01881 while( lIt != m_imports.end() ){
01882 imports += (*lIt );
01883 ++lIt;
01884 }
01885
01886 QStringList::Iterator impIt = imports.begin();
01887 while( impIt != imports.end() ){
01888 ClassDom kl = findContainer( (*impIt) + "::" + name, container, false );
01889 if( kl )
01890 return kl;
01891 ++impIt;
01892 }
01893 }
01894 #endif
01895
01896 return c;
01897 }
01898
01899 void CppCodeCompletion::computeFileEntryList( )
01900 {
01901 m_fileEntryList.clear();
01902
01903 QStringList fileList = m_pSupport->project()->allFiles();
01904 for( QStringList::Iterator it=fileList.begin(); it!=fileList.end(); ++it )
01905 {
01906 if( !m_pSupport->isHeader(*it) )
01907 continue;
01908
01909 KTextEditor::CompletionEntry entry;
01910 entry.text = QFileInfo( *it ).fileName();
01911 m_fileEntryList.push_back( entry );
01912 }
01913
01914 m_fileEntryList = unique( m_fileEntryList );
01915 }
01916
01917 #include "cppcodecompletion.moc"