Skip to content

Make sure the code completion takes both private imports and testable #20525

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion include/swift/AST/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -990,7 +990,18 @@ class SourceFile final : public FileUnit {

void addImports(ArrayRef<ImportedModuleDesc> IM);

bool hasTestableOrPrivateImport(AccessLevel accessLevel, const ValueDecl *ofDecl) const;
enum ImportQueryKind {
/// Return the results for testable or private imports.
TestableAndPrivate,
/// Return the results only for testable imports.
TestableOnly,
/// Return the results only for private imports.
PrivateOnly
};

bool
hasTestableOrPrivateImport(AccessLevel accessLevel, const ValueDecl *ofDecl,
ImportQueryKind kind = TestableAndPrivate) const;

void clearLookupCache();

Expand Down
7 changes: 5 additions & 2 deletions include/swift/IDE/CodeCompletionCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class CodeCompletionCache {
std::vector<std::string> AccessPath;
bool ResultsHaveLeadingDot;
bool ForTestableLookup;
bool ForPrivateImportLookup;
bool CodeCompleteInitsInPostfixExpr;

friend bool operator==(const Key &LHS, const Key &RHS) {
Expand All @@ -49,6 +50,7 @@ class CodeCompletionCache {
LHS.AccessPath == RHS.AccessPath &&
LHS.ResultsHaveLeadingDot == RHS.ResultsHaveLeadingDot &&
LHS.ForTestableLookup == RHS.ForTestableLookup &&
LHS.ForPrivateImportLookup == RHS.ForPrivateImportLookup &&
LHS.CodeCompleteInitsInPostfixExpr == RHS.CodeCompleteInitsInPostfixExpr;
}
};
Expand Down Expand Up @@ -106,10 +108,10 @@ template<>
struct DenseMapInfo<swift::ide::CodeCompletionCache::Key> {
using KeyTy = swift::ide::CodeCompletionCache::Key;
static inline KeyTy getEmptyKey() {
return KeyTy{"", "", {}, false, false, false};
return KeyTy{"", "", {}, false, false, false, false};
}
static inline KeyTy getTombstoneKey() {
return KeyTy{"", "", {}, true, false, false};
return KeyTy{"", "", {}, true, false, false, false};
}
static unsigned getHashValue(const KeyTy &Val) {
size_t H = 0;
Expand All @@ -119,6 +121,7 @@ struct DenseMapInfo<swift::ide::CodeCompletionCache::Key> {
H ^= std::hash<std::string>()(Piece);
H ^= std::hash<bool>()(Val.ResultsHaveLeadingDot);
H ^= std::hash<bool>()(Val.ForTestableLookup);
H ^= std::hash<bool>()(Val.ForPrivateImportLookup);
return static_cast<unsigned>(H);
}
static bool isEqual(const KeyTy &LHS, const KeyTy &RHS) {
Expand Down
23 changes: 18 additions & 5 deletions lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1389,7 +1389,8 @@ void SourceFile::addImports(ArrayRef<ImportedModuleDesc> IM) {
}

bool SourceFile::hasTestableOrPrivateImport(
AccessLevel accessLevel, const swift::ValueDecl *ofDecl) const {
AccessLevel accessLevel, const swift::ValueDecl *ofDecl,
SourceFile::ImportQueryKind queryKind) const {
auto *module = ofDecl->getModuleContext();
switch (accessLevel) {
case AccessLevel::Internal:
Expand All @@ -1399,10 +1400,19 @@ bool SourceFile::hasTestableOrPrivateImport(
// decls).
return std::any_of(
Imports.begin(), Imports.end(),
[module](ImportedModuleDesc desc) -> bool {
return desc.module.second == module &&
(desc.importOptions.contains(ImportFlags::PrivateImport) ||
desc.importOptions.contains(ImportFlags::Testable));
[module, queryKind](ImportedModuleDesc desc) -> bool {
if (queryKind == ImportQueryKind::TestableAndPrivate)
return desc.module.second == module &&
(desc.importOptions.contains(ImportFlags::PrivateImport) ||
desc.importOptions.contains(ImportFlags::Testable));
else if (queryKind == ImportQueryKind::TestableOnly)
return desc.module.second == module &&
desc.importOptions.contains(ImportFlags::Testable);
else {
assert(queryKind == ImportQueryKind::PrivateOnly);
return desc.module.second == module &&
desc.importOptions.contains(ImportFlags::PrivateImport);
}
});
case AccessLevel::Open:
return true;
Expand All @@ -1412,6 +1422,9 @@ bool SourceFile::hasTestableOrPrivateImport(
break;
}

if (queryKind == ImportQueryKind::TestableOnly)
return false;

auto *DC = ofDecl->getDeclContext();
if (!DC)
return false;
Expand Down
15 changes: 9 additions & 6 deletions lib/IDE/CodeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5946,12 +5946,15 @@ void CodeCompletionCallbacksImpl::doneParsing() {
if (!ModuleFilename.empty()) {
auto &Ctx = TheModule->getASTContext();
CodeCompletionCache::Key K{
ModuleFilename,
TheModule->getName().str(),
AccessPath,
Request.NeedLeadingDot,
SF.hasTestableOrPrivateImport(AccessLevel::Internal, TheModule),
Ctx.LangOpts.CodeCompleteInitsInPostfixExpr};
ModuleFilename, TheModule->getName().str(), AccessPath,
Request.NeedLeadingDot,
SF.hasTestableOrPrivateImport(
AccessLevel::Internal, TheModule,
SourceFile::ImportQueryKind::TestableOnly),
SF.hasTestableOrPrivateImport(
AccessLevel::Internal, TheModule,
SourceFile::ImportQueryKind::PrivateOnly),
Ctx.LangOpts.CodeCompleteInitsInPostfixExpr};

using PairType = llvm::DenseSet<swift::ide::CodeCompletionCache::Key,
llvm::DenseMapInfo<CodeCompletionCache::Key>>::iterator;
Expand Down
5 changes: 4 additions & 1 deletion lib/IDE/CodeCompletionCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ static void writeCachedModule(llvm::raw_ostream &out,
OSS << p << "\0";
OSSLE.write(K.ResultsHaveLeadingDot);
OSSLE.write(K.ForTestableLookup);
OSSLE.write(K.ForPrivateImportLookup);
OSSLE.write(K.CodeCompleteInitsInPostfixExpr);
LE.write(static_cast<uint32_t>(OSS.tell())); // Size of debug info
out.write(OSS.str().data(), OSS.str().size()); // Debug info blob
Expand Down Expand Up @@ -423,6 +424,7 @@ static std::string getName(StringRef cacheDirectory,
// name[-dot][-testable][-inits]
OSS << (K.ResultsHaveLeadingDot ? "-dot" : "")
<< (K.ForTestableLookup ? "-testable" : "")
<< (K.ForPrivateImportLookup ? "-private" : "")
<< (K.CodeCompleteInitsInPostfixExpr ? "-inits" : "");

// name[-access-path-components]
Expand Down Expand Up @@ -488,7 +490,8 @@ OnDiskCodeCompletionCache::getFromFile(StringRef filename) {
return None;

// Make up a key for readCachedModule.
CodeCompletionCache::Key K{filename, "<module-name>", {}, false, false, false};
CodeCompletionCache::Key K{filename, "<module-name>", {}, false,
false, false, false};

// Read the cached results.
auto V = CodeCompletionCache::createValue();
Expand Down
14 changes: 14 additions & 0 deletions test/IDE/complete_cache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,20 @@
// Check the individual cache item.
// RUN: %target-swift-ide-test -dump-completion-cache %t.ccp/macros-dot-* | %FileCheck %s -check-prefix=CLANG_QUAL_MACROS_2

// Qualified private with dot.
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=CLANG_QUAL_STRING -completion-cache-path=%t.ccp > %t.string.ccp1.compl.txt
// RUN: %FileCheck %s -check-prefix=CLANG_QUAL_STRING < %t.string.ccp1.compl.txt


// Ensure the testable import showed up mangled correctly.
// RUN: ls %t.ccp/Darwin-testable*
// RUN: ls %t.ccp/AppKit-private*
// REQUIRES: executable_test

import macros
import ctypes
@testable import Darwin
@_private(sourceFile: "AppKit.swift") import AppKit

// CLANG_CTYPES: Begin completions
// CLANG_CTYPES-DAG: Decl[Struct]/OtherModule[ctypes]/keyword[Foo1, Struct1]: FooStruct1[#FooStruct1#]{{; name=.+$}}
Expand Down Expand Up @@ -106,3 +113,10 @@ func testCompleteModuleQualifiedMacros2() {
// CLANG_QUAL_MACROS_2-DAG: Decl[GlobalVar]/OtherModule[macros]: .VERSION_STRING[#String#]{{; name=.+$}}
// CLANG_QUAL_MACROS_2: End completions
}

func testPrivate() {
String.#^CLANG_QUAL_STRING^#
// CLANG_QUAL_STRING: Begin completions
// CLANG_QUAL_STRING: name=someMethod()
// CLANG_QUAL_STRING: End completions
}
4 changes: 4 additions & 0 deletions test/Inputs/clang-importer-sdk/swift-modules/AppKit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@
extension String {
public static func someFactoryMethod() -> Int { return 0 }
}

extension String {
static func someMethod() -> Int { return 0 }
}