KDevelop API Documentation

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         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 /*    if( name.length() >=2 )
01004         args << Catalog::QueryArgument( "prefix", name.left(2) );*/
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     // try with parents
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             //kdDebug(9007) << "add argument " << var.name << " with type " << var.type << endl;
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     //computeContext( ctx, ast->condition(), line, col );
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             //kdDebug(9007) << "add variable " << var.name << " with type " << var.type << endl;
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 // namespace?
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     //insertRecoveryPoint( ast );
01308     m_currentScope.push_back( ast->namespaceName()->text() );
01309 
01310     m_imports.push( m_imports.top() ); // dup
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     //InitDeclaratorListAST* declarators = ast->initDeclaratorList();
01323 
01324     if( typeSpec )
01325         parseTypeSpecifier( typeSpec );
01326 
01327     //insertRecoveryPoint( ast );
01328     TreeParser::parseSimpleDeclaration( ast );
01329     }
01330 
01331     virtual void parseFunctionDefinition( FunctionDefinitionAST* ast )
01332     {
01333     m_imports.push( m_imports.top() ); // dup
01334     insertRecoveryPoint( ast );
01335     m_imports.pop();
01336     }
01337 
01338     virtual void parseClassSpecifier( ClassSpecifierAST* ast )
01339     {
01340     //insertRecoveryPoint( ast );
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     } /*else*/ {
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 /*      if( fullname.length() >=2 )
01492             args << Catalog::QueryArgument( "prefix", fullname.left(2) );*/
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 /*isInstance*/ )
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 /*isInstance*/ )
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     //entry.prefix = meth->type();
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 /*isInstance*/ )
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 /*    if( name.length() >=2 )
01698         args << Catalog::QueryArgument( "prefix", name.left(2) );    */
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 /*    if( fullname.length() >=2 )
01708         args << Catalog::QueryArgument( "prefix", fullname.left(2) );*/
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"
KDE Logo
This file is part of the documentation for KDevelop Version 3.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Feb 22 09:22:28 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003