//===---- CodeCompleteConsumer.h - Code Completion Interface ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the CodeCompleteConsumer class.
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/CodeCompleteConsumer.h"
#include "clang/AST/DeclCXX.h"
#include "clang/Parse/Scope.h"
#include "clang/Lex/Preprocessor.h"
#include "Sema.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstring>
#include <functional>
using namespace clang;
//===----------------------------------------------------------------------===//
// Code completion string implementation
//===----------------------------------------------------------------------===//
CodeCompletionString::Chunk
CodeCompletionString::Chunk::CreateText(const char *Text) {
Chunk Result;
Result.Kind = CK_Text;
char *New = new char [std::strlen(Text) + 1];
std::strcpy(New, Text);
Result.Text = New;
return Result;
}
CodeCompletionString::Chunk
CodeCompletionString::Chunk::CreateOptional(
std::auto_ptr<CodeCompletionString> Optional) {
Chunk Result;
Result.Kind = CK_Optional;
Result.Optional = Optional.release();
return Result;
}
CodeCompletionString::Chunk
CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) {
Chunk Result;
Result.Kind = CK_Placeholder;
char *New = new char [std::strlen(Placeholder) + 1];
std::strcpy(New, Placeholder);
Result.Placeholder = New;
return Result;
}
void
CodeCompletionString::Chunk::Destroy() {
switch (Kind) {
case CK_Text: delete [] Text; break;
case CK_Optional: delete Optional; break;
case CK_Placeholder: delete [] Placeholder; break;
}
}
CodeCompletionString::~CodeCompletionString() {
std::for_each(Chunks.begin(), Chunks.end(),
std::mem_fun_ref(&Chunk::Destroy));
}
std::string CodeCompletionString::getAsString() const {
std::string Result;
llvm::raw_string_ostream OS(Result);
for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) {
switch (C->Kind) {
case CK_Text: OS << C->Text; break;
case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break;
case CK_Placeholder: OS << "<#" << C->Placeholder << "#>"; break;
}
}
return Result;
}
//===----------------------------------------------------------------------===//
// Code completion consumer implementation
//===----------------------------------------------------------------------===//
CodeCompleteConsumer::CodeCompleteConsumer(Sema &S) : SemaRef(S) {
SemaRef.setCodeCompleteConsumer(this);
}
CodeCompleteConsumer::~CodeCompleteConsumer() {
SemaRef.setCodeCompleteConsumer(0);
}
void
CodeCompleteConsumer::CodeCompleteMemberReferenceExpr(Scope *S,
QualType BaseType,
bool IsArrow) {
if (IsArrow) {
if (const PointerType *Ptr = BaseType->getAs<PointerType>())
BaseType = Ptr->getPointeeType();
else if (BaseType->isObjCObjectPointerType())
/*Do nothing*/ ;
else
return;
}
ResultSet Results(*this);
unsigned NextRank = 0;
if (const RecordType *Record = BaseType->getAs<RecordType>()) {
NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank, Results);
if (getSema().getLangOptions().CPlusPlus) {
if (!Results.empty()) {
// The "template" keyword can follow "->" or "." in the grammar.
// However, we only want to suggest the template keyword if something
// is dependent.
bool IsDependent = BaseType->isDependentType();
if (!IsDependent) {
for (Scope *DepScope = S; DepScope; DepScope = DepScope->getParent())
if (DeclContext *Ctx = (DeclContext *)DepScope->getEntity()) {
IsDependent = Ctx->isDependentContext();
break;
}
}
if (IsDependent)
Results.MaybeAddResult(Result("template", NextRank++));
}
// We could have the start of a nested-name-specifier. Add those
// results as well.
Results.setFilter(&CodeCompleteConsumer::IsNestedNameSpecifier);
CollectLookupResults(S, NextRank,