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