CodeCompleteConsumer.cpp (199512) | CodeCompleteConsumer.cpp (199990) |
---|---|
1//===--- CodeCompleteConsumer.cpp - Code Completion Interface ---*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements the CodeCompleteConsumer class. 11// 12//===----------------------------------------------------------------------===// 13#include "clang/Sema/CodeCompleteConsumer.h" 14#include "clang/AST/DeclCXX.h" 15#include "clang/Parse/Scope.h" 16#include "clang/Lex/Preprocessor.h" | 1//===--- CodeCompleteConsumer.cpp - Code Completion Interface ---*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements the CodeCompleteConsumer class. 11// 12//===----------------------------------------------------------------------===// 13#include "clang/Sema/CodeCompleteConsumer.h" 14#include "clang/AST/DeclCXX.h" 15#include "clang/Parse/Scope.h" 16#include "clang/Lex/Preprocessor.h" |
17#include "clang-c/Index.h" |
|
17#include "Sema.h" 18#include "llvm/ADT/STLExtras.h" 19#include "llvm/ADT/StringSwitch.h" | 18#include "Sema.h" 19#include "llvm/ADT/STLExtras.h" 20#include "llvm/ADT/StringSwitch.h" |
20#include "llvm/Support/Compiler.h" | |
21#include "llvm/Support/raw_ostream.h" 22#include <algorithm> 23#include <cstring> 24#include <functional> 25 26using namespace clang; 27using llvm::StringRef; 28 --- 176 unchanged lines hidden (view full) --- 205 206CodeCompletionString *CodeCompletionString::Clone() const { 207 CodeCompletionString *Result = new CodeCompletionString; 208 for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) 209 Result->AddChunk(C->Clone()); 210 return Result; 211} 212 | 21#include "llvm/Support/raw_ostream.h" 22#include <algorithm> 23#include <cstring> 24#include <functional> 25 26using namespace clang; 27using llvm::StringRef; 28 --- 176 unchanged lines hidden (view full) --- 205 206CodeCompletionString *CodeCompletionString::Clone() const { 207 CodeCompletionString *Result = new CodeCompletionString; 208 for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) 209 Result->AddChunk(C->Clone()); 210 return Result; 211} 212 |
213namespace { 214 // Escape a string for XML-like formatting. 215 struct EscapedString { 216 EscapedString(llvm::StringRef Str) : Str(Str) { } 217 218 llvm::StringRef Str; 219 }; 220 221 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, EscapedString EStr) { 222 llvm::StringRef Str = EStr.Str; 223 while (!Str.empty()) { 224 // Find the next escaped character. 225 llvm::StringRef::size_type Pos = Str.find_first_of("<>&\"'"); 226 227 // Print everything before that escaped character. 228 OS << Str.substr(0, Pos); | 213static void WriteUnsigned(llvm::raw_ostream &OS, unsigned Value) { 214 OS.write((const char *)&Value, sizeof(unsigned)); 215} |
229 | 216 |
230 // If we didn't find any escaped characters, we're done. 231 if (Pos == llvm::StringRef::npos) 232 break; 233 234 // Print the appropriate escape sequence. 235 switch (Str[Pos]) { 236 case '<': OS << "<"; break; 237 case '>': OS << ">"; break; 238 case '&': OS << "&"; break; 239 case '"': OS << """; break; 240 case '\'': OS << "'"; break; 241 } 242 243 // Remove everything up to and including that escaped character. 244 Str = Str.substr(Pos + 1); 245 } 246 247 return OS; 248 } 249 250 /// \brief Remove XML-like escaping from a string. 251 std::string UnescapeString(llvm::StringRef Str) { 252 using llvm::StringRef; 253 254 std::string Result; 255 llvm::raw_string_ostream OS(Result); 256 257 while (!Str.empty()) { 258 StringRef::size_type Amp = Str.find('&'); 259 OS << Str.substr(0, Amp); 260 261 if (Amp == StringRef::npos) 262 break; 263 264 StringRef::size_type Semi = Str.substr(Amp).find(';'); 265 if (Semi == StringRef::npos) { 266 // Malformed input; do the best we can. 267 OS << '&'; 268 Str = Str.substr(Amp + 1); 269 continue; 270 } 271 272 char Unescaped = llvm::StringSwitch<char>(Str.substr(Amp + 1, Semi - 1)) 273 .Case("lt", '<') 274 .Case("gt", '>') 275 .Case("amp", '&') 276 .Case("quot", '"') 277 .Case("apos", '\'') 278 .Default('\0'); 279 280 if (Unescaped) 281 OS << Unescaped; 282 else 283 OS << Str.substr(Amp, Semi + 1); 284 Str = Str.substr(Amp + Semi + 1); 285 } 286 287 return OS.str(); 288 } | 217static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, 218 unsigned &Value) { 219 if (Memory + sizeof(unsigned) > MemoryEnd) 220 return true; 221 222 memmove(&Value, Memory, sizeof(unsigned)); 223 Memory += sizeof(unsigned); 224 return false; |
289} 290 291void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const { | 225} 226 227void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const { |
228 // Write the number of chunks. 229 WriteUnsigned(OS, size()); 230 |
|
292 for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) { | 231 for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) { |
232 WriteUnsigned(OS, C->Kind); 233 |
|
293 switch (C->Kind) { 294 case CK_TypedText: | 234 switch (C->Kind) { 235 case CK_TypedText: |
295 OS << "<typed-text>" << EscapedString(C->Text) << "</>"; 296 break; | |
297 case CK_Text: | 236 case CK_Text: |
298 OS << "<text>" << EscapedString(C->Text) << "</>"; | 237 case CK_Placeholder: 238 case CK_Informative: 239 case CK_CurrentParameter: { 240 const char *Text = C->Text; 241 unsigned StrLen = strlen(Text); 242 WriteUnsigned(OS, StrLen); 243 OS.write(Text, StrLen); |
299 break; | 244 break; |
245 } 246 |
|
300 case CK_Optional: | 247 case CK_Optional: |
301 OS << "<optional>"; | |
302 C->Optional->Serialize(OS); | 248 C->Optional->Serialize(OS); |
303 OS << "</>"; | |
304 break; | 249 break; |
305 case CK_Placeholder: 306 OS << "<placeholder>" << EscapedString(C->Text) << "</>"; 307 break; 308 case CK_Informative: 309 OS << "<informative>" << EscapedString(C->Text) << "</>"; 310 break; 311 case CK_CurrentParameter: 312 OS << "<current-parameter>" << EscapedString(C->Text) << "</>"; 313 break; | 250 |
314 case CK_LeftParen: | 251 case CK_LeftParen: |
315 OS << "<lparen/>"; 316 break; | |
317 case CK_RightParen: | 252 case CK_RightParen: |
318 OS << "<rparen/>"; 319 break; | |
320 case CK_LeftBracket: | 253 case CK_LeftBracket: |
321 OS << "<lbracket/>"; 322 break; | |
323 case CK_RightBracket: | 254 case CK_RightBracket: |
324 OS << "<rbracket/>"; 325 break; | |
326 case CK_LeftBrace: | 255 case CK_LeftBrace: |
327 OS << "<lbrace/>"; 328 break; | |
329 case CK_RightBrace: | 256 case CK_RightBrace: |
330 OS << "<rbrace/>"; 331 break; | |
332 case CK_LeftAngle: | 257 case CK_LeftAngle: |
333 OS << "<langle/>"; 334 break; | |
335 case CK_RightAngle: | 258 case CK_RightAngle: |
336 OS << "<rangle/>"; 337 break; | |
338 case CK_Comma: | 259 case CK_Comma: |
339 OS << "<comma/>"; | |
340 break; | 260 break; |
341 } | 261 } |
342 } 343} 344 | 262 } 263} 264 |
345/// \brief Parse the next XML-ish tag of the form <blah>. 346/// 347/// \param Str the string in which we're looking for the next tag. 348/// 349/// \param TagPos if successful, will be set to the start of the tag we found. 350/// 351/// \param Standalone will indicate whether this is a "standalone" tag that 352/// has no associated data, e.g., <comma/>. 353/// 354/// \param Terminator will indicate whether this is a terminating tag (that is 355/// or starts with '/'). 356/// 357/// \returns the tag itself, without the angle brackets. 358static llvm::StringRef ParseNextTag(llvm::StringRef Str, 359 llvm::StringRef::size_type &StartTag, 360 llvm::StringRef::size_type &AfterTag, 361 bool &Standalone, bool &Terminator) { 362 using llvm::StringRef; 363 364 Standalone = false; 365 Terminator = false; 366 AfterTag = StringRef::npos; 367 368 // Find the starting '<'. 369 StartTag = Str.find('<'); 370 if (StartTag == StringRef::npos) 371 return llvm::StringRef(); 372 373 // Find the corresponding '>'. 374 llvm::StringRef::size_type EndTag = Str.substr(StartTag).find('>'); 375 if (EndTag == StringRef::npos) 376 return llvm::StringRef(); 377 AfterTag = StartTag + EndTag + 1; 378 379 // Determine whether this is a terminating tag. 380 if (Str[StartTag + 1] == '/') { 381 Terminator = true; 382 Str = Str.substr(1); 383 --EndTag; 384 } 385 386 // Determine whether this is a standalone tag. 387 if (!Terminator && Str[StartTag + EndTag - 1] == '/') { 388 Standalone = true; 389 if (EndTag > 1) 390 --EndTag; 391 } | 265CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str, 266 const char *StrEnd) { 267 if (Str == StrEnd || *Str == 0) 268 return 0; |
392 | 269 |
393 return Str.substr(StartTag + 1, EndTag - 1); 394} 395 396CodeCompletionString *CodeCompletionString::Deserialize(llvm::StringRef &Str) { 397 using llvm::StringRef; 398 | |
399 CodeCompletionString *Result = new CodeCompletionString; | 270 CodeCompletionString *Result = new CodeCompletionString; |
400 401 do { 402 // Parse the next tag. 403 StringRef::size_type StartTag, AfterTag; 404 bool Standalone, Terminator; 405 StringRef Tag = ParseNextTag(Str, StartTag, AfterTag, Standalone, 406 Terminator); 407 408 if (StartTag == StringRef::npos) | 271 unsigned NumBlocks; 272 if (ReadUnsigned(Str, StrEnd, NumBlocks)) 273 return Result; 274 275 for (unsigned I = 0; I != NumBlocks; ++I) { 276 if (Str + 1 >= StrEnd) |
409 break; | 277 break; |
410 411 // Figure out what kind of chunk we have. 412 const unsigned UnknownKind = 10000; 413 unsigned Kind = llvm::StringSwitch<unsigned>(Tag) 414 .Case("typed-text", CK_TypedText) 415 .Case("text", CK_Text) 416 .Case("optional", CK_Optional) 417 .Case("placeholder", CK_Placeholder) 418 .Case("informative", CK_Informative) 419 .Case("current-parameter", CK_CurrentParameter) 420 .Case("lparen", CK_LeftParen) 421 .Case("rparen", CK_RightParen) 422 .Case("lbracket", CK_LeftBracket) 423 .Case("rbracket", CK_RightBracket) 424 .Case("lbrace", CK_LeftBrace) 425 .Case("rbrace", CK_RightBrace) 426 .Case("langle", CK_LeftAngle) 427 .Case("rangle", CK_RightAngle) 428 .Case("comma", CK_Comma) 429 .Default(UnknownKind); 430 431 // If we've hit a terminator tag, we're done. 432 if (Terminator) 433 break; 434 435 // Consume the tag. 436 Str = Str.substr(AfterTag); | |
437 | 278 |
438 // Handle standalone tags now, since they don't need to be matched to 439 // anything. 440 if (Standalone) { 441 // Ignore anything we don't know about. 442 if (Kind == UnknownKind) 443 continue; 444 445 switch ((ChunkKind)Kind) { 446 case CK_TypedText: 447 case CK_Text: 448 case CK_Optional: 449 case CK_Placeholder: 450 case CK_Informative: 451 case CK_CurrentParameter: 452 // There is no point in creating empty chunks of these kinds. 453 break; 454 455 case CK_LeftParen: 456 case CK_RightParen: 457 case CK_LeftBracket: 458 case CK_RightBracket: 459 case CK_LeftBrace: 460 case CK_RightBrace: 461 case CK_LeftAngle: 462 case CK_RightAngle: 463 case CK_Comma: 464 Result->AddChunk(Chunk((ChunkKind)Kind)); 465 break; 466 } 467 468 continue; | 279 // Parse the next kind. 280 unsigned KindValue; 281 if (ReadUnsigned(Str, StrEnd, KindValue)) 282 return Result; 283 284 switch (ChunkKind Kind = (ChunkKind)KindValue) { 285 case CK_TypedText: 286 case CK_Text: 287 case CK_Placeholder: 288 case CK_Informative: 289 case CK_CurrentParameter: { 290 unsigned StrLen; 291 if (ReadUnsigned(Str, StrEnd, StrLen) || (Str + StrLen > StrEnd)) 292 return Result; 293 294 Result->AddChunk(Chunk(Kind, StringRef(Str, StrLen))); 295 Str += StrLen; 296 break; |
469 } | 297 } |
470 471 if (Kind == CK_Optional) { 472 // Deserialize the optional code-completion string. 473 std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str)); | 298 299 case CK_Optional: { 300 std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str, StrEnd)); |
474 Result->AddOptionalChunk(Optional); | 301 Result->AddOptionalChunk(Optional); |
302 break; |
|
475 } | 303 } |
476 477 StringRef EndTag = ParseNextTag(Str, StartTag, AfterTag, Standalone, 478 Terminator); 479 if (StartTag == StringRef::npos || !Terminator || Standalone) 480 break; // Parsing failed; just give up. 481 482 if (EndTag.empty() || Tag == EndTag) { 483 // Found the matching end tag. Add this chunk based on the text 484 // between the tags, then consume that input. 485 StringRef Text = Str.substr(0, StartTag); 486 switch ((ChunkKind)Kind) { 487 case CK_TypedText: 488 case CK_Text: 489 case CK_Placeholder: 490 case CK_Informative: 491 case CK_CurrentParameter: 492 case CK_LeftParen: 493 case CK_RightParen: 494 case CK_LeftBracket: 495 case CK_RightBracket: 496 case CK_LeftBrace: 497 case CK_RightBrace: 498 case CK_LeftAngle: 499 case CK_RightAngle: 500 case CK_Comma: 501 Result->AddChunk(Chunk((ChunkKind)Kind, UnescapeString(Text))); 502 break; 503 504 case CK_Optional: 505 // We've already added the optional chunk. 506 break; 507 } | 304 305 case CK_LeftParen: 306 case CK_RightParen: 307 case CK_LeftBracket: 308 case CK_RightBracket: 309 case CK_LeftBrace: 310 case CK_RightBrace: 311 case CK_LeftAngle: 312 case CK_RightAngle: 313 case CK_Comma: 314 Result->AddChunk(Chunk(Kind)); 315 break; |
508 } | 316 } |
509 510 // Remove this tag. 511 Str = Str.substr(AfterTag); 512 } while (!Str.empty()); | 317 }; |
513 514 return Result; 515} 516 517void CodeCompleteConsumer::Result::Destroy() { 518 if (Kind == RK_Pattern) { 519 delete Pattern; 520 Pattern = 0; --- 107 unchanged lines hidden (view full) --- 628} 629 630void 631CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, 632 Result *Results, 633 unsigned NumResults) { 634 // Print the results. 635 for (unsigned I = 0; I != NumResults; ++I) { | 318 319 return Result; 320} 321 322void CodeCompleteConsumer::Result::Destroy() { 323 if (Kind == RK_Pattern) { 324 delete Pattern; 325 Pattern = 0; --- 107 unchanged lines hidden (view full) --- 433} 434 435void 436CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, 437 Result *Results, 438 unsigned NumResults) { 439 // Print the results. 440 for (unsigned I = 0; I != NumResults; ++I) { |
636 OS << "COMPLETION:" << Results[I].Rank << ":"; | 441 CXCursorKind Kind = CXCursor_NotImplemented; 442 |
637 switch (Results[I].Kind) { | 443 switch (Results[I].Kind) { |
638 case Result::RK_Declaration: 639 if (RecordDecl *Record = dyn_cast<RecordDecl>(Results[I].Declaration)) { 640 if (Record->isStruct()) 641 OS << "Struct:"; 642 else if (Record->isUnion()) 643 OS << "Union:"; 644 else 645 OS << "Class:"; 646 } else if (ObjCMethodDecl *Method 647 = dyn_cast<ObjCMethodDecl>(Results[I].Declaration)) { 648 if (Method->isInstanceMethod()) 649 OS << "ObjCInstanceMethod:"; 650 else 651 OS << "ObjCClassMethod:"; 652 } else { 653 OS << Results[I].Declaration->getDeclKindName() << ":"; 654 } 655 if (CodeCompletionString *CCS 656 = Results[I].CreateCodeCompletionString(SemaRef)) { 657 CCS->Serialize(OS); 658 delete CCS; 659 } else { 660 OS << "<typed-text>" 661 << Results[I].Declaration->getNameAsString() 662 << "</>"; 663 } | 444 case Result::RK_Declaration: 445 switch (Results[I].Declaration->getKind()) { 446 case Decl::Record: 447 case Decl::CXXRecord: 448 case Decl::ClassTemplateSpecialization: { 449 RecordDecl *Record = cast<RecordDecl>(Results[I].Declaration); 450 if (Record->isStruct()) 451 Kind = CXCursor_StructDecl; 452 else if (Record->isUnion()) 453 Kind = CXCursor_UnionDecl; 454 else 455 Kind = CXCursor_ClassDecl; 456 break; 457 } |
664 | 458 |
665 OS << '\n'; | 459 case Decl::ObjCMethod: { 460 ObjCMethodDecl *Method = cast<ObjCMethodDecl>(Results[I].Declaration); 461 if (Method->isInstanceMethod()) 462 Kind = CXCursor_ObjCInstanceMethodDecl; 463 else 464 Kind = CXCursor_ObjCClassMethodDecl; |
666 break; | 465 break; |
466 } |
|
667 | 467 |
668 case Result::RK_Keyword: 669 OS << "Keyword:<typed-text>" << Results[I].Keyword << "</>\n"; | 468 case Decl::Typedef: 469 Kind = CXCursor_TypedefDecl; |
670 break; 671 | 470 break; 471 |
672 case Result::RK_Macro: { 673 OS << "Macro:"; 674 if (CodeCompletionString *CCS 675 = Results[I].CreateCodeCompletionString(SemaRef)) { 676 CCS->Serialize(OS); 677 delete CCS; 678 } else { 679 OS << "<typed-text>" << Results[I].Macro->getName() << "</>"; 680 } 681 OS << '\n'; | 472 case Decl::Enum: 473 Kind = CXCursor_EnumDecl; |
682 break; | 474 break; |
683 } | |
684 | 475 |
685 case Result::RK_Pattern: { 686 OS << "Pattern:"; 687 Results[I].Pattern->Serialize(OS); 688 OS << '\n'; | 476 case Decl::Field: 477 Kind = CXCursor_FieldDecl; |
689 break; | 478 break; |
479 480 case Decl::EnumConstant: 481 Kind = CXCursor_EnumConstantDecl; 482 break; 483 484 case Decl::Function: 485 case Decl::CXXMethod: 486 case Decl::CXXConstructor: 487 case Decl::CXXDestructor: 488 case Decl::CXXConversion: 489 Kind = CXCursor_FunctionDecl; 490 break; 491 492 case Decl::Var: 493 Kind = CXCursor_VarDecl; 494 break; 495 496 case Decl::ParmVar: 497 Kind = CXCursor_ParmDecl; 498 break; 499 500 case Decl::ObjCInterface: 501 Kind = CXCursor_ObjCInterfaceDecl; 502 break; 503 504 case Decl::ObjCCategory: 505 Kind = CXCursor_ObjCCategoryDecl; 506 break; 507 508 case Decl::ObjCProtocol: 509 Kind = CXCursor_ObjCProtocolDecl; 510 break; 511 512 case Decl::ObjCProperty: 513 Kind = CXCursor_ObjCPropertyDecl; 514 break; 515 516 case Decl::ObjCIvar: 517 Kind = CXCursor_ObjCIvarDecl; 518 break; 519 520 case Decl::ObjCImplementation: 521 Kind = CXCursor_ObjCClassDefn; 522 break; 523 524 case Decl::ObjCCategoryImpl: 525 Kind = CXCursor_ObjCCategoryDefn; 526 break; 527 528 default: 529 break; |
|
690 } | 530 } |
531 break; 532 533 case Result::RK_Keyword: 534 case Result::RK_Macro: 535 case Result::RK_Pattern: 536 Kind = CXCursor_NotImplemented; 537 break; |
|
691 } | 538 } |
539 540 WriteUnsigned(OS, Kind); 541 CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(SemaRef); 542 assert(CCS && "No code-completion string?"); 543 CCS->Serialize(OS); 544 delete CCS; |
|
692 } 693 694 // Once we've printed the code-completion results, suppress remaining 695 // diagnostics. 696 // FIXME: Move this somewhere else! 697 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); 698} 699 700void 701CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, 702 unsigned CurrentArg, 703 OverloadCandidate *Candidates, 704 unsigned NumCandidates) { 705 for (unsigned I = 0; I != NumCandidates; ++I) { | 545 } 546 547 // Once we've printed the code-completion results, suppress remaining 548 // diagnostics. 549 // FIXME: Move this somewhere else! 550 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); 551} 552 553void 554CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, 555 unsigned CurrentArg, 556 OverloadCandidate *Candidates, 557 unsigned NumCandidates) { 558 for (unsigned I = 0; I != NumCandidates; ++I) { |
706 if (CodeCompletionString *CCS 707 = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) { 708 OS << "OVERLOAD:"; 709 CCS->Serialize(OS); 710 OS << '\n'; 711 delete CCS; 712 } | 559 WriteUnsigned(OS, CXCursor_NotImplemented); 560 CodeCompletionString *CCS 561 = Candidates[I].CreateSignatureString(CurrentArg, SemaRef); 562 assert(CCS && "No code-completion string?"); 563 CCS->Serialize(OS); 564 delete CCS; |
713 } 714 715 // Once we've printed the code-completion results, suppress remaining 716 // diagnostics. 717 // FIXME: Move this somewhere else! 718 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); 719} | 565 } 566 567 // Once we've printed the code-completion results, suppress remaining 568 // diagnostics. 569 // FIXME: Move this somewhere else! 570 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); 571} |