[CodeCompletion] Avoid typechecking all toplevel decls in the current file

- Use `performParseAndResolveImportsOnly()` to invoke the frontend
- Do `bindExtensions()` in `ide::typeCheckContextUntil()`
- Typecheck preceding `TopLevelCodeDecl`s only if the compleiton is in
  a `TopLevelCodeDecl`
- Other related tweaks

rdar://problem/56636747
This commit is contained in:
Rintaro Ishizaki
2019-10-30 17:13:16 -07:00
parent 9203080c0e
commit 2564a6e494
13 changed files with 109 additions and 39 deletions

View File

@@ -4138,10 +4138,47 @@ public:
void addAccessControl(const ValueDecl *VD,
CodeCompletionResultBuilder &Builder) {
assert(CurrDeclContext->getSelfNominalTypeDecl());
auto AccessOfContext =
CurrDeclContext->getSelfNominalTypeDecl()->getFormalAccess();
auto Access = std::min(VD->getFormalAccess(), AccessOfContext);
auto CurrentNominal = CurrDeclContext->getSelfNominalTypeDecl();
assert(CurrentNominal);
auto AccessOfContext = CurrentNominal->getFormalAccess();
if (AccessOfContext < AccessLevel::Public)
return;
auto Access = VD->getFormalAccess();
// Use the greater access between the protocol requirement and the witness.
// In case of:
//
// public protocol P { func foo() }
// public class B { func foo() {} }
// public class C: B, P {
// <complete>
// }
//
// 'VD' is 'B.foo()' which is implicitly 'internal'. But as the overriding
// declaration, the user needs to write both 'public' and 'override':
//
// public class C: B {
// public override func foo() {}
// }
if (Access < AccessLevel::Public &&
!isa<ProtocolDecl>(VD->getDeclContext())) {
for (auto Conformance : CurrentNominal->getAllConformances()) {
auto Proto = Conformance->getProtocol();
for (auto Member : Proto->getMembers()) {
auto Requirement = dyn_cast<ValueDecl>(Member);
if (!Requirement || !Requirement->isProtocolRequirement() ||
isa<AssociatedTypeDecl>(Requirement))
continue;
auto Witness = Conformance->getWitnessDecl(Requirement);
if (Witness == VD)
Access = std::max(Access, Requirement->getFormalAccess());
}
}
}
Access = std::min(Access, AccessOfContext);
// Only emit 'public', not needed otherwise.
if (Access >= AccessLevel::Public)
Builder.addAccessControlKeyword(Access);
@@ -4364,9 +4401,11 @@ public:
if (D->shouldHideFromEditor())
return;
if (D->isFinal() ||
// A 'class' member with an initial value cannot be overriden either.
(D->isStatic() && D->getAttrs().hasAttribute<HasInitialValueAttr>()))
if (D->isFinal())
return;
// A 'class' member with an initial value cannot be overriden either.
if (D->isStatic() && isa<VarDecl>(D) && cast<VarDecl>(D)->hasInitialValue())
return;
bool hasIntroducer = hasFuncIntroducer ||
@@ -4955,13 +4994,16 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
case CompletionKind::TypeIdentifierWithoutDot:
break;
case CompletionKind::TypeDeclResultBeginning:
if (!isa<ProtocolDecl>(CurDeclContext))
if (CurDeclContext->isTypeContext() ||
(ParsedDecl && isa<FuncDecl>(ParsedDecl)))
case CompletionKind::TypeDeclResultBeginning: {
auto DC = CurDeclContext;
if (ParsedDecl && ParsedDecl == CurDeclContext->getAsDecl())
DC = ParsedDecl->getDeclContext();
if (!isa<ProtocolDecl>(DC))
if (DC->isTypeContext() || (ParsedDecl && isa<FuncDecl>(ParsedDecl)))
addOpaqueTypeKeyword(Sink);
LLVM_FALLTHROUGH;
}
case CompletionKind::TypeSimpleBeginning:
addAnyTypeKeyword(Sink);
break;
@@ -5130,8 +5172,6 @@ void CodeCompletionCallbacksImpl::doneParsing() {
CD->getContextKind() == DeclContextKind::TopLevelCodeDecl)
MaybeFuncBody = false;
}
// Add keywords even if type checking fails completely.
addKeywords(CompletionContext.getResultSink(), MaybeFuncBody);
if (auto *DC = dyn_cast_or_null<DeclContext>(ParsedDecl)) {
if (DC->isChildContextOf(CurDeclContext))
@@ -5142,6 +5182,9 @@ void CodeCompletionCallbacksImpl::doneParsing() {
CurDeclContext,
CurDeclContext->getASTContext().SourceMgr.getCodeCompletionLoc());
// Add keywords even if type checking fails completely.
addKeywords(CompletionContext.getResultSink(), MaybeFuncBody);
Optional<Type> ExprType;
ConcreteDeclRef ReferencedDecl = nullptr;
if (ParsedExpr) {