Skip to content

Commit 09121f7

Browse files
committed
[AST] Move getInterfaceHashIncludingTypeMembers() to SourceFile
1 parent 1b6e785 commit 09121f7

File tree

3 files changed

+47
-45
lines changed

3 files changed

+47
-45
lines changed

include/swift/AST/SourceFile.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,9 @@ class SourceFile final : public FileUnit {
531531
out << getInterfaceHash() << '\n';
532532
}
533533

534+
/// Get this file's interface hash including the type members in the file.
535+
Fingerprint getInterfaceHashIncludingTypeMembers() const;
536+
534537
/// If this source file has been told to collect its parsed tokens, retrieve
535538
/// those tokens.
536539
ArrayRef<Token> getAllTokens() const;

lib/AST/Module.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,30 @@ Fingerprint SourceFile::getInterfaceHash() const {
10991099
return Fingerprint{std::move(result)};
11001100
}
11011101

1102+
Fingerprint SourceFile::getInterfaceHashIncludingTypeMembers() const {
1103+
/// FIXME: Gross. Hashing multiple "hash" values.
1104+
llvm::MD5 hash;
1105+
hash.update(getInterfaceHash().getRawValue());
1106+
1107+
std::function<void(IterableDeclContext *)> hashTypeBodyFingerprints =
1108+
[&](IterableDeclContext *IDC) {
1109+
if (auto fp = IDC->getBodyFingerprint())
1110+
hash.update(fp->getRawValue());
1111+
for (auto *member : IDC->getParsedMembers())
1112+
if (auto *childIDC = dyn_cast<IterableDeclContext>(member))
1113+
hashTypeBodyFingerprints(childIDC);
1114+
};
1115+
1116+
for (auto *D : getTopLevelDecls()) {
1117+
if (auto IDC = dyn_cast<IterableDeclContext>(D))
1118+
hashTypeBodyFingerprints(IDC);
1119+
}
1120+
1121+
llvm::MD5::MD5Result result;
1122+
hash.final(result);
1123+
return Fingerprint{std::move(result)};
1124+
}
1125+
11021126
syntax::SourceFileSyntax SourceFile::getSyntaxRoot() const {
11031127
assert(shouldBuildSyntaxTree() && "Syntax tree disabled");
11041128
auto &eval = getASTContext().evaluator;

lib/IDE/CompletionInstance.cpp

Lines changed: 20 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -277,49 +277,6 @@ static bool areAnyDependentFilesInvalidated(
277277
});
278278
}
279279

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

325282
bool CompletionInstance::performCachedOperationIfPossible(
@@ -396,8 +353,26 @@ bool CompletionInstance::performCachedOperationIfPossible(
396353
switch (newInfo.Kind) {
397354
case CodeCompletionDelayedDeclKind::FunctionBody: {
398355
// If the interface has changed, AST must be refreshed.
399-
const auto oldInterfaceHash = getInterfaceHashIncludingTypeMembers(oldSF);
400-
const auto newInterfaceHash = getInterfaceHashIncludingTypeMembers(tmpSF);
356+
// See if the inteface of the function and types visible from a function
357+
// body has changed since the last completion. If they haven't changed,
358+
// completion can reuse the existing AST of the source file.
359+
// \c getInterfaceHash() is not enough because it doesn't take the interface
360+
// of the type members into account. For example:
361+
//
362+
// struct S {
363+
// func foo() {}
364+
// }
365+
// func main(val: S) {
366+
// val.<HERE>
367+
// }
368+
//
369+
// In this case, we need to ensure that the interface of \c S hasn't
370+
// changed. Note that we don't care about local types (i.e. type
371+
// declarations inside function bodies, closures, or top level statement
372+
// bodies) because they are not visible from other functions where the
373+
// completion is happening.
374+
const auto oldInterfaceHash = oldSF->getInterfaceHashIncludingTypeMembers();
375+
const auto newInterfaceHash = tmpSF->getInterfaceHashIncludingTypeMembers();
401376
if (oldInterfaceHash != newInterfaceHash)
402377
return false;
403378

0 commit comments

Comments
 (0)