Skip to content

Commit 1696f4d

Browse files
authored
Merge pull request #34256 from rintaro/ide-completion-rdar69890297
[CodeCompletion] Remove parser hacks regarding type body fingerprints
2 parents be38df8 + df94c4f commit 1696f4d

File tree

2 files changed

+52
-11
lines changed

2 files changed

+52
-11
lines changed

lib/IDE/CompletionInstance.cpp

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,51 @@ static bool areAnyDependentFilesInvalidated(
276276
});
277277
}
278278

279+
/// Get interface hash of \p SF including the type members in the file.
280+
///
281+
/// See if the inteface of the function and types visible from a function body
282+
/// has changed since the last completion. If they haven't changed, completion
283+
/// can reuse the existing AST of the source file. \c SF->getInterfaceHash() is
284+
/// not enough because it doesn't take the interface of the type members into
285+
/// account. For example:
286+
///
287+
/// struct S {
288+
/// func foo() {}
289+
/// }
290+
/// func main(val: S) {
291+
/// val.<HERE>
292+
/// }
293+
///
294+
/// In this case, we need to ensure that the interface of \c S hasn't changed.
295+
/// Note that we don't care about local types (i.e. type declarations inside
296+
/// function bodies, closures, or top level statement bodies) because they are
297+
/// not visible from other functions where the completion is happening.
298+
void getInterfaceHashIncludingTypeMembers(SourceFile *SF,
299+
llvm::SmallString<32> &str) {
300+
/// FIXME: Gross. Hashing multiple "hash" values.
301+
llvm::MD5 hash;
302+
SF->getInterfaceHash(str);
303+
hash.update(str);
304+
305+
std::function<void(IterableDeclContext *)> hashTypeBodyFingerprints =
306+
[&](IterableDeclContext *IDC) {
307+
if (auto fp = IDC->getBodyFingerprint())
308+
hash.update(*fp);
309+
for (auto *member : IDC->getParsedMembers())
310+
if (auto *childIDC = dyn_cast<IterableDeclContext>(member))
311+
hashTypeBodyFingerprints(childIDC);
312+
};
313+
314+
for (auto *D : SF->getTopLevelDecls()) {
315+
if (auto IDC = dyn_cast<IterableDeclContext>(D))
316+
hashTypeBodyFingerprints(IDC);
317+
}
318+
319+
llvm::MD5::MD5Result result;
320+
hash.final(result);
321+
str = result.digest();
322+
}
323+
279324
} // namespace
280325

281326
bool CompletionInstance::performCachedOperationIfPossible(
@@ -355,8 +400,8 @@ bool CompletionInstance::performCachedOperationIfPossible(
355400
// If the interface has changed, AST must be refreshed.
356401
llvm::SmallString<32> oldInterfaceHash{};
357402
llvm::SmallString<32> newInterfaceHash{};
358-
oldSF->getInterfaceHash(oldInterfaceHash);
359-
tmpSF->getInterfaceHash(newInterfaceHash);
403+
getInterfaceHashIncludingTypeMembers(oldSF, oldInterfaceHash);
404+
getInterfaceHashIncludingTypeMembers(tmpSF, newInterfaceHash);
360405
if (oldInterfaceHash != newInterfaceHash)
361406
return false;
362407

@@ -406,6 +451,10 @@ bool CompletionInstance::performCachedOperationIfPossible(
406451
Scope Top(SI, ScopeKind::TopLevel);
407452
Scope Body(SI, ScopeKind::FunctionBody);
408453

454+
assert(oldInfo.Kind == CodeCompletionDelayedDeclKind::FunctionBody &&
455+
"If the interface hash is the same as old one, the previous kind "
456+
"must be FunctionBody too. Otherwise, hashing is too weak");
457+
oldInfo.Kind = CodeCompletionDelayedDeclKind::FunctionBody;
409458
oldInfo.ParentContext = DC;
410459
oldInfo.StartOffset = newInfo.StartOffset;
411460
oldInfo.EndOffset = newInfo.EndOffset;

lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4672,13 +4672,8 @@ Parser::parseDeclList(SourceLoc LBLoc, SourceLoc &RBLoc, Diag<> ErrorDiag,
46724672

46734673
// If we're hashing the type body separately, record the curly braces but
46744674
// nothing inside for the interface hash.
4675-
//
4676-
// FIXME: There's no real reason code completion cannot also use this code
4677-
// path. But it seems to cause lazy parsing in contexts that the current
4678-
// implementation does not expect.
46794675
Optional<llvm::SaveAndRestore<Optional<llvm::MD5>>> MemberHashingScope;
4680-
if (IDC->areTokensHashedForThisBodyInsteadOfInterfaceHash() &&
4681-
!L->isCodeCompletion()) {
4676+
if (IDC->areTokensHashedForThisBodyInsteadOfInterfaceHash()) {
46824677
recordTokenHash("{");
46834678
recordTokenHash("}");
46844679
MemberHashingScope.emplace(CurrentTokenHash, llvm::MD5());
@@ -4713,9 +4708,6 @@ Parser::parseDeclList(SourceLoc LBLoc, SourceLoc &RBLoc, Diag<> ErrorDiag,
47134708
if (RBLoc.isInvalid())
47144709
hadError = true;
47154710

4716-
if (L->isCodeCompletion())
4717-
return std::make_pair(decls, None);
4718-
47194711
llvm::MD5::MD5Result result;
47204712
auto declListHash = MemberHashingScope ? *CurrentTokenHash : llvm::MD5();
47214713
declListHash.final(result);

0 commit comments

Comments
 (0)