Skip to content

Commit

Permalink
Reapply "[CodeComplete] Teach code completion engine to recognize and…
Browse files Browse the repository at this point in the history
… manifest @recommended and @recommendedover." after fixing a linux failure. (thanks, Dmitri)
  • Loading branch information
nkcsgexi committed Nov 10, 2015
1 parent 8858503 commit 22ba61b
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 59 deletions.
14 changes: 7 additions & 7 deletions include/swift/IDE/CodeCompletion.h
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ class CodeCompletionResult {
StringRef ModuleName;
StringRef BriefDocComment;
ArrayRef<StringRef> AssociatedUSRs;
ArrayRef<StringRef> Keywords;
ArrayRef<std::pair<StringRef, StringRef>> DocWords;
unsigned TypeDistance : 3;

public:
Expand Down Expand Up @@ -558,14 +558,14 @@ class CodeCompletionResult {
const Decl *AssociatedDecl, StringRef ModuleName,
bool NotRecommended, StringRef BriefDocComment,
ArrayRef<StringRef> AssociatedUSRs,
ArrayRef<StringRef> Keywords,
ArrayRef<std::pair<StringRef, StringRef>> DocWords,
enum ExpectedTypeRelation TypeDistance)
: Kind(ResultKind::Declaration),
SemanticContext(unsigned(SemanticContext)),
NotRecommended(NotRecommended), NumBytesToErase(NumBytesToErase),
CompletionString(CompletionString), ModuleName(ModuleName),
BriefDocComment(BriefDocComment), AssociatedUSRs(AssociatedUSRs),
Keywords(Keywords), TypeDistance(TypeDistance) {
DocWords(DocWords), TypeDistance(TypeDistance) {
assert(AssociatedDecl && "should have a decl");
AssociatedKind = unsigned(getCodeCompletionDeclKind(AssociatedDecl));
assert(CompletionString);
Expand All @@ -578,13 +578,13 @@ class CodeCompletionResult {
CodeCompletionDeclKind DeclKind, StringRef ModuleName,
bool NotRecommended, StringRef BriefDocComment,
ArrayRef<StringRef> AssociatedUSRs,
ArrayRef<StringRef> Keywords)
ArrayRef<std::pair<StringRef, StringRef>> DocWords)
: Kind(ResultKind::Declaration),
SemanticContext(unsigned(SemanticContext)),
NotRecommended(NotRecommended), NumBytesToErase(NumBytesToErase),
CompletionString(CompletionString), ModuleName(ModuleName),
BriefDocComment(BriefDocComment), AssociatedUSRs(AssociatedUSRs),
Keywords(Keywords) {
DocWords(DocWords) {
AssociatedKind = static_cast<unsigned>(DeclKind);
assert(CompletionString);
TypeDistance = ExpectedTypeRelation::Unrelated;
Expand Down Expand Up @@ -650,8 +650,8 @@ class CodeCompletionResult {
return AssociatedUSRs;
}

ArrayRef<StringRef> getDeclKeywords() const {
return Keywords;
ArrayRef<std::pair<StringRef, StringRef>> getDeclKeywords() const {
return DocWords;
}

/// Print a debug representation of the code completion result to \p OS.
Expand Down
160 changes: 134 additions & 26 deletions lib/IDE/CodeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,55 @@ using namespace ide;

namespace clang {
namespace comments {

enum CodeCompletionCommandKind {
none,
keyword,
recommended,
recommendedover,
};

typedef std::vector<std::pair<StringRef, StringRef>> CommandWordsPairs;

class WordPairsArrangedViewer {
ArrayRef<std::pair<StringRef, StringRef>> Content;
std::vector<StringRef> ViewedText;
std::vector<StringRef> Words;
StringRef Key;

bool isKeyViewed(StringRef K) {
return std::find(ViewedText.begin(), ViewedText.end(), K) != ViewedText.end();
}

public:
WordPairsArrangedViewer(ArrayRef<std::pair<StringRef, StringRef>> Content):
Content(Content) {}

bool hasNext() {
Words.clear();
bool Found = false;
for (auto P : Content) {
if (!Found && !isKeyViewed(P.first)) {
Key = P.first;
Found = true;
}
if (Found && P.first == Key)
Words.push_back(P.second);
}
return Found;
}

std::pair<StringRef, ArrayRef<StringRef>> next() {
bool HasNext = hasNext();
assert(HasNext && "Have no more data.");
ViewedText.push_back(Key);
return std::make_pair(Key, llvm::makeArrayRef(Words));
}
};

class ClangCommentExtractor : public ConstCommentVisitor<ClangCommentExtractor> {
std::vector<StringRef> &Keywords;
CommandWordsPairs &Words;
const CommandTraits &Traits;
std::string Keyword = "keyword";
std::vector<const Comment *> Parents;

void visitChildren(const Comment* C) {
Expand All @@ -59,9 +104,33 @@ class ClangCommentExtractor : public ConstCommentVisitor<ClangCommentExtractor>
Parents.pop_back();
}

StringRef getCommnadName(CodeCompletionCommandKind Kind) {
#define CHECK_CASE(KIND) \
if (CodeCompletionCommandKind::KIND == Kind) { \
static std::string Name(#KIND); \
return Name; \
}
CHECK_CASE(keyword)
CHECK_CASE(recommended)
CHECK_CASE(recommendedover)
#undef CHECK_CASE
llvm_unreachable("Can not handle this Kind.");
}

CodeCompletionCommandKind getCommandKind(StringRef Command) {
#define CHECK_CASE(KIND) \
if (Command == #KIND) \
return CodeCompletionCommandKind::KIND;
CHECK_CASE(keyword);
CHECK_CASE(recommended);
CHECK_CASE(recommendedover);
#undef CHECK_CASE
return CodeCompletionCommandKind::none;
}

public:
ClangCommentExtractor(std::vector<StringRef> &Keywords,
const CommandTraits &Traits) : Keywords(Keywords),
ClangCommentExtractor(CommandWordsPairs &Words,
const CommandTraits &Traits) : Words(Words),
Traits(Traits) {}
#define CHILD_VISIT(NAME) \
void visit##NAME(const NAME *C) {\
Expand All @@ -73,7 +142,8 @@ class ClangCommentExtractor : public ConstCommentVisitor<ClangCommentExtractor>

void visitInlineCommandComment(const InlineCommandComment *C) {
auto Command = C->getCommandName(Traits);
if (Command != Keyword)
auto CommandKind = getCommandKind(Command);
if (CommandKind == CodeCompletionCommandKind::none)
return;
auto &Parent = Parents.back();
for (auto CIT = std::find(Parent->child_begin(), Parent->child_end(), C) + 1;
Expand All @@ -84,7 +154,7 @@ class ClangCommentExtractor : public ConstCommentVisitor<ClangCommentExtractor>
auto Pair = Text.split(',');
auto Key = Pair.first.trim();
if (!Key.empty())
Keywords.push_back(Key);
Words.push_back(std::make_pair(getCommnadName(CommandKind), Key));
Text = Pair.second;
} while (!Text.empty());
} else
Expand All @@ -93,13 +163,27 @@ class ClangCommentExtractor : public ConstCommentVisitor<ClangCommentExtractor>
}
};

bool containsInterestedWords(StringRef Content) {
do {
Content = Content.split('@').second;
#define CHECK_CASE(KIND) \
if (Content.startswith(#KIND)) \
return true;
CHECK_CASE(keyword)
CHECK_CASE(recommended)
CHECK_CASE(recommendedover)
#undef CHECK_CASE
} while(!Content.empty());
return false;
}

void getClangDocKeyword(ClangImporter &Importer, const Decl *D,
std::vector<StringRef> &Keywords) {
ClangCommentExtractor Extractor(Keywords, Importer.getClangASTContext().
CommandWordsPairs &Words) {
ClangCommentExtractor Extractor(Words, Importer.getClangASTContext().
getCommentCommandTraits());
if (auto RC = Importer.getClangASTContext().getRawCommentForAnyRedecl(D)) {
auto RT = RC->getRawText(Importer.getClangASTContext().getSourceManager());
if (RT.find("@keyword") != StringRef::npos) {
if (containsInterestedWords(RT)) {
FullComment* Comment = Importer.getClangASTContext().
getLocalCommentForDeclUncached(D);
Extractor.visit(Comment);
Expand Down Expand Up @@ -533,10 +617,14 @@ void CodeCompletionResult::print(raw_ostream &OS) const {
break;
}

if (!Keywords.empty()) {
Prefix.append("/Keywords[");
for (clang::comments::WordPairsArrangedViewer Viewer(DocWords);
Viewer.hasNext();) {
auto Pair = Viewer.next();
Prefix.append("/");
Prefix.append(Pair.first);
Prefix.append("[");
StringRef Sep = ", ";
for (auto KW : Keywords) {
for (auto KW : Pair.second) {
Prefix.append(KW);
Prefix.append(Sep);
}
Expand Down Expand Up @@ -571,6 +659,18 @@ static ArrayRef<StringRef> copyStringArray(llvm::BumpPtrAllocator &Allocator,
return llvm::makeArrayRef(Buff, Arr.size());
}

static ArrayRef<std::pair<StringRef, StringRef>> copyStringPairArray(
llvm::BumpPtrAllocator &Allocator,
ArrayRef<std::pair<StringRef, StringRef>> Arr) {
std::pair<StringRef, StringRef> *Buff = Allocator.Allocate<std::pair<StringRef,
StringRef>>(Arr.size());
for (unsigned I = 0; I < Arr.size(); ++I) {
Buff[I].first = Arr[I].first;
Buff[I].second = Arr[I].second;
}
return llvm::makeArrayRef(Buff, Arr.size());
}

void CodeCompletionResultBuilder::addChunkWithText(
CodeCompletionString::Chunk::ChunkKind Kind, StringRef Text) {
addChunkWithTextNoCopy(Kind, copyString(*Sink.Allocator, Text));
Expand Down Expand Up @@ -734,7 +834,7 @@ CodeCompletionResult *CodeCompletionResultBuilder::takeResult() {
SemanticContext, NumBytesToErase, CCS, AssociatedDecl, ModuleName,
/*NotRecommended=*/false, copyString(*Sink.Allocator, BriefComment),
copyAssociatedUSRs(*Sink.Allocator, AssociatedDecl),
copyStringArray(*Sink.Allocator, DeclKeywords), typeRelation);
copyStringPairArray(*Sink.Allocator, CommentWords), typeRelation);
}

case CodeCompletionResult::ResultKind::Keyword:
Expand Down Expand Up @@ -1310,11 +1410,11 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
}

void setClangDeclKeywords(const ValueDecl *VD,
clang::comments::CommandWordsPairs &Pairs,
CodeCompletionResultBuilder &Builder) {
if (auto *CD = VD->getClangDecl()) {
std::vector<StringRef> Keywords;
clang::comments::getClangDocKeyword(*Importer, CD, Keywords);
Builder.addDeclKeywords(Keywords);
clang::comments::getClangDocKeyword(*Importer, CD, Pairs);
Builder.addDeclDocCommentWords(Pairs);
}
}

Expand Down Expand Up @@ -1609,14 +1709,15 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
"name lookup bug -- can not see an instance variable "
"in a static function");

clang::comments::CommandWordsPairs Pairs;
CodeCompletionResultBuilder Builder(
Sink,
CodeCompletionResult::ResultKind::Declaration,
getSemanticContext(VD, Reason), ExpectedTypes);
Builder.setAssociatedDecl(VD);
addLeadingDot(Builder);
Builder.addTextChunk(Name);
setClangDeclKeywords(VD, Builder);
setClangDeclKeywords(VD, Pairs, Builder);
// Add a type annotation.
Type VarType = getTypeOfMember(VD);
if (VD->getName() == Ctx.Id_self) {
Expand Down Expand Up @@ -1913,10 +2014,11 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {

// Add the method, possibly including any default arguments.
auto addMethodImpl = [&](bool includeDefaultArgs = true) {
clang::comments::CommandWordsPairs Pairs;
CodeCompletionResultBuilder Builder(
Sink, CodeCompletionResult::ResultKind::Declaration,
getSemanticContext(FD, Reason), ExpectedTypes);
setClangDeclKeywords(FD, Builder);
setClangDeclKeywords(FD, Pairs, Builder);
Builder.setAssociatedDecl(FD);
addLeadingDot(Builder);
Builder.addTextChunk(Name);
Expand Down Expand Up @@ -2008,10 +2110,11 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {

// Add the constructor, possibly including any default arguments.
auto addConstructorImpl = [&](bool includeDefaultArgs = true) {
clang::comments::CommandWordsPairs Pairs;
CodeCompletionResultBuilder Builder(
Sink, CodeCompletionResult::ResultKind::Declaration,
getSemanticContext(CD, Reason), ExpectedTypes);
setClangDeclKeywords(CD, Builder);
setClangDeclKeywords(CD, Pairs, Builder);
Builder.setAssociatedDecl(CD);
if (needInit) {
assert(addName.empty());
Expand Down Expand Up @@ -2080,12 +2183,13 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {

void addSubscriptCall(const SubscriptDecl *SD, DeclVisibilityKind Reason) {
assert(!HaveDot && "can not add a subscript after a dot");
clang::comments::CommandWordsPairs Pairs;
CodeCompletionResultBuilder Builder(
Sink,
CodeCompletionResult::ResultKind::Declaration,
getSemanticContext(SD, Reason), ExpectedTypes);
Builder.setAssociatedDecl(SD);
setClangDeclKeywords(SD, Builder);
setClangDeclKeywords(SD, Pairs, Builder);
Builder.addLeftBracket();
addPatternParameters(Builder, SD->getIndices());
Builder.addRightBracket();
Expand All @@ -2102,24 +2206,26 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {

void addNominalTypeRef(const NominalTypeDecl *NTD,
DeclVisibilityKind Reason) {
clang::comments::CommandWordsPairs Pairs;
CodeCompletionResultBuilder Builder(
Sink,
CodeCompletionResult::ResultKind::Declaration,
getSemanticContext(NTD, Reason), ExpectedTypes);
Builder.setAssociatedDecl(NTD);
setClangDeclKeywords(NTD, Builder);
setClangDeclKeywords(NTD, Pairs, Builder);
addLeadingDot(Builder);
Builder.addTextChunk(NTD->getName().str());
addTypeAnnotation(Builder, NTD->getDeclaredType());
}

void addTypeAliasRef(const TypeAliasDecl *TAD, DeclVisibilityKind Reason) {
clang::comments::CommandWordsPairs Pairs;
CodeCompletionResultBuilder Builder(
Sink,
CodeCompletionResult::ResultKind::Declaration,
getSemanticContext(TAD, Reason), ExpectedTypes);
Builder.setAssociatedDecl(TAD);
setClangDeclKeywords(TAD, Builder);
setClangDeclKeywords(TAD, Pairs, Builder);
addLeadingDot(Builder);
Builder.addTextChunk(TAD->getName().str());
if (TAD->hasUnderlyingType() && !TAD->getUnderlyingType()->is<ErrorType>())
Expand All @@ -2131,11 +2237,12 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {

void addGenericTypeParamRef(const GenericTypeParamDecl *GP,
DeclVisibilityKind Reason) {
clang::comments::CommandWordsPairs Pairs;
CodeCompletionResultBuilder Builder(
Sink,
CodeCompletionResult::ResultKind::Declaration,
getSemanticContext(GP, Reason), ExpectedTypes);
setClangDeclKeywords(GP, Builder);
setClangDeclKeywords(GP, Pairs, Builder);
Builder.setAssociatedDecl(GP);
addLeadingDot(Builder);
Builder.addTextChunk(GP->getName().str());
Expand All @@ -2144,11 +2251,12 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {

void addAssociatedTypeRef(const AssociatedTypeDecl *AT,
DeclVisibilityKind Reason) {
clang::comments::CommandWordsPairs Pairs;
CodeCompletionResultBuilder Builder(
Sink,
CodeCompletionResult::ResultKind::Declaration,
getSemanticContext(AT, Reason), ExpectedTypes);
setClangDeclKeywords(AT, Builder);
setClangDeclKeywords(AT, Pairs, Builder);
Builder.setAssociatedDecl(AT);
addLeadingDot(Builder);
Builder.addTextChunk(AT->getName().str());
Expand All @@ -2161,14 +2269,14 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
bool HasTypeContext) {
if (!EED->hasName())
return;

clang::comments::CommandWordsPairs Pairs;
CodeCompletionResultBuilder Builder(
Sink,
CodeCompletionResult::ResultKind::Declaration,
HasTypeContext ? SemanticContextKind::ExpressionSpecific
: getSemanticContext(EED, Reason), ExpectedTypes);
Builder.setAssociatedDecl(EED);
setClangDeclKeywords(EED, Builder);
setClangDeclKeywords(EED, Pairs, Builder);
addLeadingDot(Builder);
Builder.addTextChunk(EED->getName().str());
if (EED->hasArgumentType())
Expand Down
Loading

0 comments on commit 22ba61b

Please sign in to comment.