CodeCompleteConsumer.cpp revision 0594438e06f58ab3798416324780ab39ca9c8f54
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/Support/Compiler.h" 20#include "llvm/Support/raw_ostream.h" 21#include <algorithm> 22#include <cstring> 23#include <functional> 24using namespace clang; 25 26//===----------------------------------------------------------------------===// 27// Code completion string implementation 28//===----------------------------------------------------------------------===// 29CodeCompletionString::Chunk::Chunk(ChunkKind Kind, const char *Text) 30 : Kind(Kind), Text(0) 31{ 32 assert((Kind == CK_Text || Kind == CK_Placeholder || Kind == CK_Informative) 33 && "Invalid text chunk kind"); 34 char *New = new char [std::strlen(Text) + 1]; 35 std::strcpy(New, Text); 36 this->Text = New; 37} 38 39CodeCompletionString::Chunk 40CodeCompletionString::Chunk::CreateText(const char *Text) { 41 return Chunk(CK_Text, Text); 42} 43 44CodeCompletionString::Chunk 45CodeCompletionString::Chunk::CreateOptional( 46 std::auto_ptr<CodeCompletionString> Optional) { 47 Chunk Result; 48 Result.Kind = CK_Optional; 49 Result.Optional = Optional.release(); 50 return Result; 51} 52 53CodeCompletionString::Chunk 54CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) { 55 return Chunk(CK_Placeholder, Placeholder); 56} 57 58CodeCompletionString::Chunk 59CodeCompletionString::Chunk::CreateInformative(const char *Informative) { 60 return Chunk(CK_Informative, Informative); 61} 62 63void 64CodeCompletionString::Chunk::Destroy() { 65 switch (Kind) { 66 case CK_Optional: 67 delete Optional; 68 break; 69 70 case CK_Text: 71 case CK_Placeholder: 72 case CK_Informative: 73 delete [] Text; 74 break; 75 } 76} 77 78CodeCompletionString::~CodeCompletionString() { 79 std::for_each(Chunks.begin(), Chunks.end(), 80 std::mem_fun_ref(&Chunk::Destroy)); 81} 82 83std::string CodeCompletionString::getAsString() const { 84 std::string Result; 85 llvm::raw_string_ostream OS(Result); 86 87 for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) { 88 switch (C->Kind) { 89 case CK_Text: OS << C->Text; break; 90 case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break; 91 case CK_Placeholder: OS << "<#" << C->Text << "#>"; break; 92 case CK_Informative: OS << "[#" << C->Text << "#]"; break; 93 } 94 } 95 96 return Result; 97} 98 99//===----------------------------------------------------------------------===// 100// Code completion overload candidate implementation 101//===----------------------------------------------------------------------===// 102FunctionDecl * 103CodeCompleteConsumer::OverloadCandidate::getFunction() const { 104 if (getKind() == CK_Function) 105 return Function; 106 else if (getKind() == CK_FunctionTemplate) 107 return FunctionTemplate->getTemplatedDecl(); 108 else 109 return 0; 110} 111 112const FunctionType * 113CodeCompleteConsumer::OverloadCandidate::getFunctionType() const { 114 switch (Kind) { 115 case CK_Function: 116 return Function->getType()->getAs<FunctionType>(); 117 118 case CK_FunctionTemplate: 119 return FunctionTemplate->getTemplatedDecl()->getType() 120 ->getAs<FunctionType>(); 121 122 case CK_FunctionType: 123 return Type; 124 } 125 126 return 0; 127} 128 129//===----------------------------------------------------------------------===// 130// Code completion consumer implementation 131//===----------------------------------------------------------------------===// 132 133CodeCompleteConsumer::~CodeCompleteConsumer() { } 134 135void 136PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results, 137 unsigned NumResults) { 138 // Print the results. 139 for (unsigned I = 0; I != NumResults; ++I) { 140 switch (Results[I].Kind) { 141 case Result::RK_Declaration: 142 OS << Results[I].Declaration->getNameAsString() << " : " 143 << Results[I].Rank; 144 if (Results[I].Hidden) 145 OS << " (Hidden)"; 146 if (CodeCompletionString *CCS 147 = Results[I].CreateCodeCompletionString(SemaRef)) { 148 OS << " : " << CCS->getAsString(); 149 delete CCS; 150 } 151 152 OS << '\n'; 153 break; 154 155 case Result::RK_Keyword: 156 OS << Results[I].Keyword << " : " << Results[I].Rank << '\n'; 157 break; 158 } 159 } 160 161 // Once we've printed the code-completion results, suppress remaining 162 // diagnostics. 163 // FIXME: Move this somewhere else! 164 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); 165} 166 167void 168PrintingCodeCompleteConsumer::ProcessOverloadCandidates(unsigned CurrentArg, 169 OverloadCandidate *Candidates, 170 unsigned NumCandidates) { 171 for (unsigned I = 0; I != NumCandidates; ++I) { 172 std::string ArgString; 173 QualType ArgType; 174 175 if (FunctionDecl *Function = Candidates[I].getFunction()) { 176 if (CurrentArg < Function->getNumParams()) { 177 ArgString = Function->getParamDecl(CurrentArg)->getNameAsString(); 178 ArgType = Function->getParamDecl(CurrentArg)->getOriginalType(); 179 } 180 } else if (const FunctionProtoType *Proto 181 = dyn_cast<FunctionProtoType>( 182 Candidates[I].getFunctionType())) { 183 if (CurrentArg < Proto->getNumArgs()) 184 ArgType = Proto->getArgType(CurrentArg); 185 } 186 187 if (ArgType.isNull()) 188 OS << "...\n"; // We have no prototype or we're matching an ellipsis. 189 else { 190 ArgType.getAsStringInternal(ArgString, SemaRef.Context.PrintingPolicy); 191 OS << ArgString << "\n"; 192 } 193 } 194 195 // Once we've printed the code-completion results, suppress remaining 196 // diagnostics. 197 // FIXME: Move this somewhere else! 198 SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); 199} 200