CodeCompleteConsumer.cpp revision 92eff466867fd6a82fb3e245f2091e96a3e9888e
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 "Sema.h" 18#include "llvm/ADT/STLExtras.h" 19#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 29//===----------------------------------------------------------------------===// 30// Code completion string implementation 31//===----------------------------------------------------------------------===// 32CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text) 33 : Kind(Kind), Text("") 34{ 35 switch (Kind) { 36 case CK_TypedText: 37 case CK_Text: 38 case CK_Placeholder: 39 case CK_Informative: 40 case CK_CurrentParameter: { 41 char *New = new char [Text.size() + 1]; 42 std::memcpy(New, Text.data(), Text.size()); 43 New[Text.size()] = '\0'; 44 this->Text = New; 45 break; 46 } 47 48 case CK_Optional: 49 llvm::llvm_unreachable("Optional strings cannot be created from text"); 50 break; 51 52 case CK_LeftParen: 53 this->Text = "("; 54 break; 55 56 case CK_RightParen: 57 this->Text = ")"; 58 break; 59 60 case CK_LeftBracket: 61 this->Text = "["; 62 break; 63 64 case CK_RightBracket: 65 this->Text = "]"; 66 break; 67 68 case CK_LeftBrace: 69 this->Text = "{"; 70 break; 71 72 case CK_RightBrace: 73 this->Text = "}"; 74 break; 75 76 case CK_LeftAngle: 77 this->Text = "<"; 78 break; 79 80 case CK_RightAngle: 81 this->Text = ">"; 82 break; 83 84 case CK_Comma: 85 this->Text = ", "; 86 break; 87 } 88} 89 90CodeCompletionString::Chunk 91CodeCompletionString::Chunk::CreateText(StringRef Text) { 92 return Chunk(CK_Text, Text); 93} 94 95CodeCompletionString::Chunk 96CodeCompletionString::Chunk::CreateOptional( 97 std::auto_ptr<CodeCompletionString> Optional) { 98 Chunk Result; 99 Result.Kind = CK_Optional; 100 Result.Optional = Optional.release(); 101 return Result; 102} 103 104CodeCompletionString::Chunk 105CodeCompletionString::Chunk::CreatePlaceholder(StringRef Placeholder) { 106 return Chunk(CK_Placeholder, Placeholder); 107} 108 109CodeCompletionString::Chunk 110CodeCompletionString::Chunk::CreateInformative(StringRef Informative) { 111 return Chunk(CK_Informative, Informative); 112} 113 114CodeCompletionString::Chunk 115CodeCompletionString::Chunk::CreateCurrentParameter( 116 StringRef CurrentParameter) { 117 return Chunk(CK_CurrentParameter, CurrentParameter); 118} 119 120 121void 122CodeCompletionString::Chunk::Destroy() { 123 switch (Kind) { 124 case CK_Optional: 125 delete Optional; 126 break; 127 128 case CK_TypedText: 129 case CK_Text: 130 case CK_Placeholder: 131 case CK_Informative: 132 case CK_CurrentParameter: 133 delete [] Text; 134 break; 135 136 case CK_LeftParen: 137 case CK_RightParen: 138 case CK_LeftBracket: 139 case CK_RightBracket: 140 case CK_LeftBrace: 141 case CK_RightBrace: 142 case CK_LeftAngle: 143 case CK_RightAngle: 144 case CK_Comma: 145 break; 146 } 147} 148 149CodeCompletionString::~CodeCompletionString() { 150 std::for_each(Chunks.begin(), Chunks.end(), 151 std::mem_fun_ref(&Chunk::Destroy)); 152} 153 154std::string CodeCompletionString::getAsString() const { 155 std::string Result; 156 llvm::raw_string_ostream OS(Result); 157 158 for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) { 159 switch (C->Kind) { 160 case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break; 161 case CK_Placeholder: OS << "<#" << C->Text << "#>"; break; 162 case CK_Informative: OS << "[#" << C->Text << "#]"; break; 163 case CK_CurrentParameter: OS << "<#" << C->Text << "#>"; break; 164 default: OS << C->Text; break; 165 } 166 } 167 OS.flush(); 168 return Result; 169} 170 171 172namespace { 173 // Escape a string for XML-like formatting. 174 struct EscapedString { 175 EscapedString(llvm::StringRef Str) : Str(Str) { } 176 177 llvm::StringRef Str; 178 }; 179 180 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, EscapedString EStr) { 181 llvm::StringRef Str = EStr.Str; 182 while (!Str.empty()) { 183 // Find the next escaped character. 184 llvm::StringRef::size_type Pos = Str.find_first_of("<>&\"'"); 185 186 // Print everything before that escaped character. 187 OS << Str.substr(0, Pos); 188 189 // If we didn't find any escaped characters, we're done. 190 if (Pos == llvm::StringRef::npos) 191 break; 192 193 // Print the appropriate escape sequence. 194 switch (Str[Pos]) { 195 case '<': OS << "<"; break; 196 case '>': OS << ">"; break; 197 case '&': OS << "&"; break; 198 case '"': OS << """; break; 199 case '\'': OS << "'"; break; 200 } 201 202 // Remove everything up to and including that escaped character. 203 Str = Str.substr(Pos + 1); 204 } 205 206 return OS; 207 } 208 209 /// \brief Remove XML-like escaping from a string. 210 std::string UnescapeString(llvm::StringRef Str) { 211 using llvm::StringRef; 212 213 std::string Result; 214 llvm::raw_string_ostream OS(Result); 215 216 while (!Str.empty()) { 217 StringRef::size_type Amp = Str.find('&'); 218 OS << Str.substr(0, Amp); 219 220 if (Amp == StringRef::npos) 221 break; 222 223 StringRef::size_type Semi = Str.substr(Amp).find(';'); 224 if (Semi == StringRef::npos) { 225 // Malformed input; do the best we can. 226 OS << '&'; 227 Str = Str.substr(Amp + 1); 228 continue; 229 } 230 231 char Unescaped = llvm::StringSwitch<char>(Str.substr(Amp + 1, Semi - 1)) 232 .Case("lt", '<') 233 .Case("gt", '>') 234 .Case("amp", '&') 235 .Case("quot", '"') 236 .Case("apos", '\'') 237 .Default('\0'); 238 239 if (Unescaped) 240 OS << Unescaped; 241 else 242 OS << Str.substr(Amp, Semi + 1); 243 Str = Str.substr(Amp + Semi + 1); 244 } 245 246 return OS.str(); 247 } 248} 249 250void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const { 251 for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) { 252 switch (C->Kind) { 253 case CK_TypedText: 254 OS << "<typed-text>" << EscapedString(C->Text) << "</>"; 255 break; 256 case CK_Text: 257 OS << "<text>" << EscapedString(C->Text) << "</>"; 258 break; 259 case CK_Optional: 260 OS << "<optional>"; 261 C->Optional->Serialize(OS); 262 OS << "</>"; 263 break; 264 case CK_Placeholder: 265 OS << "<placeholder>" << EscapedString(C->Text) << "</>"; 266 break; 267 case CK_Informative: 268 OS << "<informative>" << EscapedString(C->Text) << "</>"; 269 break; 270 case CK_CurrentParameter: 271 OS << "<current-parameter>" << EscapedString(C->Text) << "</>"; 272 break; 273 case CK_LeftParen: 274 OS << "<lparen/>"; 275 break; 276 case CK_RightParen: 277 OS << "<rparen/>"; 278 break; 279 case CK_LeftBracket: 280 OS << "<lbracket/>"; 281 break; 282 case CK_RightBracket: 283 OS << "<rbracket/>"; 284 break; 285 case CK_LeftBrace: 286 OS << "<lbrace/>"; 287 break; 288 case CK_RightBrace: 289 OS << "<rbrace/>"; 290 break; 291 case CK_LeftAngle: 292 OS << "<langle/>"; 293 break; 294 case CK_RightAngle: 295 OS << "<rangle/>"; 296 break; 297 case CK_Comma: 298 OS << "<comma/>"; 299 break; 300 } 301 } 302} 303 304/// \brief Parse the next XML-ish tag of the form <blah>. 305/// 306/// \param Str the string in which we're looking for the next tag. 307/// 308/// \param TagPos if successful, will be set to the start of the tag we found. 309/// 310/// \param Standalone will indicate whether this is a "standalone" tag that 311/// has no associated data, e.g., <comma/>. 312/// 313/// \param Terminator will indicate whether this is a terminating tag (that is 314/// or starts with '/'). 315/// 316/// \returns the tag itself, without the angle brackets. 317static llvm::StringRef ParseNextTag(llvm::StringRef Str, 318 llvm::StringRef::size_type &StartTag, 319 llvm::StringRef::size_type &AfterTag, 320 bool &Standalone, bool &Terminator) { 321 using llvm::StringRef; 322 323 Standalone = false; 324 Terminator = false; 325 AfterTag = StringRef::npos; 326 327 // Find the starting '<'. 328 StartTag = Str.find('<'); 329 if (StartTag == StringRef::npos) 330 return llvm::StringRef(); 331 332 // Find the corresponding '>'. 333 llvm::StringRef::size_type EndTag = Str.substr(StartTag).find('>'); 334 if (EndTag == StringRef::npos) 335 return llvm::StringRef(); 336 AfterTag = StartTag + EndTag + 1; 337 338 // Determine whether this is a terminating tag. 339 if (Str[StartTag + 1] == '/') { 340 Terminator = true; 341 Str = Str.substr(1); 342 --EndTag; 343 } 344 345 // Determine whether this is a standalone tag. 346 if (!Terminator && Str[StartTag + EndTag - 1] == '/') { 347 Standalone = true; 348 if (EndTag > 1) 349 --EndTag; 350 } 351 352 return Str.substr(StartTag + 1, EndTag - 1); 353} 354 355CodeCompletionString *CodeCompletionString::Deserialize(llvm::StringRef &Str) { 356 using llvm::StringRef; 357 358 CodeCompletionString *Result = new CodeCompletionString; 359 360 do { 361 // Parse the next tag. 362 StringRef::size_type StartTag, AfterTag; 363 bool Standalone, Terminator; 364 StringRef Tag = ParseNextTag(Str, StartTag, AfterTag, Standalone, 365 Terminator); 366 367 if (StartTag == StringRef::npos) 368 break; 369 370 // Figure out what kind of chunk we have. 371 const unsigned UnknownKind = 10000; 372 unsigned Kind = llvm::StringSwitch<unsigned>(Tag) 373 .Case("typed-text", CK_TypedText) 374 .Case("text", CK_Text) 375 .Case("optional", CK_Optional) 376 .Case("placeholder", CK_Placeholder) 377 .Case("informative", CK_Informative) 378 .Case("current-parameter", CK_CurrentParameter) 379 .Case("lparen", CK_LeftParen) 380 .Case("rparen", CK_RightParen) 381 .Case("lbracket", CK_LeftBracket) 382 .Case("rbracket", CK_RightBracket) 383 .Case("lbrace", CK_LeftBrace) 384 .Case("rbrace", CK_RightBrace) 385 .Case("langle", CK_LeftAngle) 386 .Case("rangle", CK_RightAngle) 387 .Case("comma", CK_Comma) 388 .Default(UnknownKind); 389 390 // If we've hit a terminator tag, we're done. 391 if (Terminator) 392 break; 393 394 // Consume the tag. 395 Str = Str.substr(AfterTag); 396 397 // Handle standalone tags now, since they don't need to be matched to 398 // anything. 399 if (Standalone) { 400 // Ignore anything we don't know about. 401 if (Kind == UnknownKind) 402 continue; 403 404 switch ((ChunkKind)Kind) { 405 case CK_TypedText: 406 case CK_Text: 407 case CK_Optional: 408 case CK_Placeholder: 409 case CK_Informative: 410 case CK_CurrentParameter: 411 // There is no point in creating empty chunks of these kinds. 412 break; 413 414 case CK_LeftParen: 415 case CK_RightParen: 416 case CK_LeftBracket: 417 case CK_RightBracket: 418 case CK_LeftBrace: 419 case CK_RightBrace: 420 case CK_LeftAngle: 421 case CK_RightAngle: 422 case CK_Comma: 423 Result->AddChunk(Chunk((ChunkKind)Kind)); 424 break; 425 } 426 427 continue; 428 } 429 430 if (Kind == CK_Optional) { 431 // Deserialize the optional code-completion string. 432 std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str)); 433 Result->AddOptionalChunk(Optional); 434 } 435 436 StringRef EndTag = ParseNextTag(Str, StartTag, AfterTag, Standalone, 437 Terminator); 438 if (StartTag == StringRef::npos || !Terminator || Standalone) 439 break; // Parsing failed; just give up. 440 441 if (EndTag.empty() || Tag == EndTag) { 442 // Found the matching end tag. Add this chunk based on the text 443 // between the tags, then consume that input. 444 StringRef Text = Str.substr(0, StartTag); 445 switch ((ChunkKind)Kind) { 446 case CK_TypedText: 447 case CK_Text: 448 case CK_Placeholder: 449 case CK_Informative: 450 case CK_CurrentParameter: 451 case CK_LeftParen: 452 case CK_RightParen: 453 case CK_LeftBracket: 454 case CK_RightBracket: 455 case CK_LeftBrace: 456 case CK_RightBrace: 457 case CK_LeftAngle: 458 case CK_RightAngle: 459 case CK_Comma: 460 Result->AddChunk(Chunk((ChunkKind)Kind, UnescapeString(Text))); 461 break; 462 463 case CK_Optional: 464 // We've already added the optional chunk. 465 break; 466 } 467 } 468 469 // Remove this tag. 470 Str = Str.substr(AfterTag); 471 } while (!Str.empty()); 472 473 return Result; 474} 475 476//===----------------------------------------------------------------------===// 477// Code completion overload candidate implementation 478//===----------------------------------------------------------------------===// 479FunctionDecl * 480CodeCompleteConsumer::OverloadCandidate::getFunction() const { 481 if (getKind() == CK_Function) 482 return Function; 483 else if (getKind() == CK_FunctionTemplate) 484 return FunctionTemplate->getTemplatedDecl(); 485 else 486 return 0; 487} 488 489const FunctionType * 490CodeCompleteConsumer::OverloadCandidate::getFunctionType() const { 491 switch (Kind) { 492 case CK_Function: 493 return Function->getType()->getAs<FunctionType>(); 494 495 case CK_FunctionTemplate: 496 return FunctionTemplate->getTemplatedDecl()->getType() 497 ->getAs<FunctionType>(); 498 499 case CK_FunctionType: 500 return Type; 501 } 502 503 return 0; 504} 505 506//===----------------------------------------------------------------------===// 507// Code completion consumer implementation 508//===----------------------------------------------------------------------===// 509 510CodeCompleteConsumer::~CodeCompleteConsumer() { } 511 512void 513PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, 514 Result *Results, 515 unsigned NumResults) { 516 // Print the results. 517 for (unsigned I = 0; I != NumResults; ++I) { 518 OS << "COMPLETION: "; 519 switch (Results[I].Kind) { 520 case Result::RK_Declaration: 521 OS << Results[I].Declaration->getNameAsString() << " : " 522 << Results[I].Rank; 523 if (Results[I].Hidden) 524 OS << " (Hidden)"; 525 if (CodeCompletionString *CCS 526 = Results[I].CreateCodeCompletionString(SemaRef)) { 527 OS << " : " << CCS->getAsString(); 528 delete CCS; 529 } 530 531 OS << '\n'; 532 break; 533 534 case Result::RK_Keyword: 535 OS << Results[I].Keyword << " : " << Results[I].Rank << '\n'; 536 break; 537 538 case Result::RK_Macro: { 539 OS << Results[I].Macro->getName() << " : " << Results[I].Rank; 540 if (CodeCompletionString *CCS 541 = Results[I].CreateCodeCompletionString(SemaRef)) { 542 OS << " : " << CCS->getAsString(); 543 delete CCS; 544 } 545 OS << '\n'; 546 break; 547 } 548 } 549 } 550 551 // Once we've printed the code-completion results, suppress remaining 552 // diagnostics. 553 // FIXME: Move this somewhere else! 554 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); 555} 556 557void 558PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, 559 unsigned CurrentArg, 560 OverloadCandidate *Candidates, 561 unsigned NumCandidates) { 562 for (unsigned I = 0; I != NumCandidates; ++I) { 563 if (CodeCompletionString *CCS 564 = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) { 565 OS << "OVERLOAD: " << CCS->getAsString() << "\n"; 566 delete CCS; 567 } 568 } 569 570 // Once we've printed the code-completion results, suppress remaining 571 // diagnostics. 572 // FIXME: Move this somewhere else! 573 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); 574} 575 576void 577CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, 578 Result *Results, 579 unsigned NumResults) { 580 // Print the results. 581 for (unsigned I = 0; I != NumResults; ++I) { 582 OS << "COMPLETION:" << Results[I].Rank << ":"; 583 switch (Results[I].Kind) { 584 case Result::RK_Declaration: 585 if (RecordDecl *Record = dyn_cast<RecordDecl>(Results[I].Declaration)) { 586 if (Record->isStruct()) 587 OS << "Struct:"; 588 else if (Record->isUnion()) 589 OS << "Union:"; 590 else 591 OS << "Class:"; 592 } else if (ObjCMethodDecl *Method 593 = dyn_cast<ObjCMethodDecl>(Results[I].Declaration)) { 594 if (Method->isInstanceMethod()) 595 OS << "ObjCInstanceMethod:"; 596 else 597 OS << "ObjCClassMethod:"; 598 } else { 599 OS << Results[I].Declaration->getDeclKindName() << ":"; 600 } 601 if (CodeCompletionString *CCS 602 = Results[I].CreateCodeCompletionString(SemaRef)) { 603 CCS->Serialize(OS); 604 delete CCS; 605 } else { 606 OS << "<typed-text>" 607 << Results[I].Declaration->getNameAsString() 608 << "</>"; 609 } 610 611 OS << '\n'; 612 break; 613 614 case Result::RK_Keyword: 615 OS << "Keyword:<typed-text>" << Results[I].Keyword << "</>\n"; 616 break; 617 618 case Result::RK_Macro: { 619 OS << "Macro:"; 620 if (CodeCompletionString *CCS 621 = Results[I].CreateCodeCompletionString(SemaRef)) { 622 CCS->Serialize(OS); 623 delete CCS; 624 } else { 625 OS << "<typed-text>" << Results[I].Macro->getName() << "</>"; 626 } 627 OS << '\n'; 628 break; 629 } 630 } 631 } 632 633 // Once we've printed the code-completion results, suppress remaining 634 // diagnostics. 635 // FIXME: Move this somewhere else! 636 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); 637} 638 639void 640CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, 641 unsigned CurrentArg, 642 OverloadCandidate *Candidates, 643 unsigned NumCandidates) { 644 for (unsigned I = 0; I != NumCandidates; ++I) { 645 if (CodeCompletionString *CCS 646 = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) { 647 OS << "OVERLOAD:"; 648 CCS->Serialize(OS); 649 OS << '\n'; 650 delete CCS; 651 } 652 } 653 654 // Once we've printed the code-completion results, suppress remaining 655 // diagnostics. 656 // FIXME: Move this somewhere else! 657 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); 658} 659