Merge pull request #62366 from ahoppen/ahoppen/solver-based-cursor-info-prep-pt-3

[IDE] Allow typeCheckASTNodeAtLoc to type check declarations
This commit is contained in:
Alex Hoppen
2022-12-06 09:05:23 +01:00
committed by GitHub
2 changed files with 53 additions and 9 deletions

View File

@@ -174,6 +174,25 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks {
/// \returns true on success, false on failure.
bool typecheckParsedType() {
// If the type appeared inside an extension, make sure that extension has
// been bound.
auto SF = CurDeclContext->getParentSourceFile();
auto visitTopLevelDecl = [&](Decl *D) {
if (auto ED = dyn_cast<ExtensionDecl>(D)) {
if (ED->getSourceRange().contains(ParsedTypeLoc.getLoc())) {
ED->computeExtendedNominal();
}
}
};
for (auto item : SF->getTopLevelItems()) {
if (auto D = item.dyn_cast<Decl *>()) {
visitTopLevelDecl(D);
}
}
for (auto *D : SF->getHoistedDecls()) {
visitTopLevelDecl(D);
}
assert(ParsedTypeLoc.getTypeRepr() && "should have a TypeRepr");
if (ParsedTypeLoc.wasValidated() && !ParsedTypeLoc.isError()) {
return true;
@@ -1576,11 +1595,14 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
return;
undoSingleExpressionReturn(CurDeclContext);
typeCheckContextAt(
TypeCheckASTNodeAtLocContext::declContext(CurDeclContext),
ParsedExpr
? ParsedExpr->getLoc()
: CurDeclContext->getASTContext().SourceMgr.getCodeCompletionLoc());
if (Kind != CompletionKind::TypeIdentifierWithDot) {
// Type member completion does not need a type-checked AST.
typeCheckContextAt(
TypeCheckASTNodeAtLocContext::declContext(CurDeclContext),
ParsedExpr
? ParsedExpr->getLoc()
: CurDeclContext->getASTContext().SourceMgr.getCodeCompletionLoc());
}
// Add keywords even if type checking fails completely.
addKeywords(CompletionContext.getResultSink(), MaybeFuncBody);

View File

@@ -1933,9 +1933,19 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(
if (!braceCharRange.contains(Loc))
return Action::SkipChildren(S);
// Reset the node found in a parent context.
if (!brace->isImplicit())
FoundNode = nullptr;
// Reset the node found in a parent context if it's not part of this
// brace statement.
// We must not reset FoundNode if it's inside thei BraceStmt's source
// range because the found node could be inside a capture list, which is
// syntactically part of the brace stmt's range but won't be walked as
// a child of the brace stmt.
if (!brace->isImplicit() && FoundNode) {
auto foundNodeCharRange = Lexer::getCharSourceRangeFromSourceRange(
SM, FoundNode->getSourceRange());
if (!braceCharRange.contains(foundNodeCharRange)) {
FoundNode = nullptr;
}
}
for (ASTNode &node : brace->getElements()) {
if (SM.isBeforeInBuffer(Loc, node.getStartLoc()))
@@ -1992,6 +2002,18 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(
PreWalkAction walkToDeclPre(Decl *D) override {
if (auto *newDC = dyn_cast<DeclContext>(D))
DC = newDC;
if (!SM.isBeforeInBuffer(Loc, D->getStartLoc())) {
// NOTE: We need to check the character loc here because the target
// loc can be inside the last token of the node. i.e. interpolated
// string.
SourceLoc endLoc = Lexer::getLocForEndOfToken(SM, D->getEndLoc());
if (!(SM.isBeforeInBuffer(endLoc, Loc) || endLoc == Loc)) {
if (!isa<TopLevelCodeDecl>(D)) {
FoundNode = new ASTNode(D);
}
}
}
return Action::Continue();
}
@@ -2005,7 +2027,7 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(
}
// Nothing found at the location, or the decl context does not own the 'Loc'.
if (finder.isNull())
if (finder.isNull() || !finder.getDeclContext())
return true;
DeclContext *DC = finder.getDeclContext();