Skip to content

[SourceKit] add qualified types in type requests #61246

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 2 commits into from
Oct 4, 2022
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
10 changes: 5 additions & 5 deletions include/swift/Sema/IDETypeChecking.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,11 +231,10 @@ namespace swift {

/// Collect type information for every expression in \c SF; all types will
/// be printed to \c OS.
ArrayRef<ExpressionTypeInfo> collectExpressionType(SourceFile &SF,
ArrayRef<const char *> ExpectedProtocols,
std::vector<ExpressionTypeInfo> &scratch,
bool CanonicalType,
llvm::raw_ostream &OS);
ArrayRef<ExpressionTypeInfo> collectExpressionType(
SourceFile &SF, ArrayRef<const char *> ExpectedProtocols,
std::vector<ExpressionTypeInfo> &scratch, bool FullyQualified,
bool CanonicalType, llvm::raw_ostream &OS);

/// Resolve a list of mangled names to accessible protocol decls from
/// the decl context.
Expand Down Expand Up @@ -265,6 +264,7 @@ namespace swift {
/// \c VariableTypeInfos will index into the string that backs this
/// stream.
void collectVariableType(SourceFile &SF, SourceRange Range,
bool FullyQualified,
std::vector<VariableTypeInfo> &VariableTypeInfos,
llvm::raw_ostream &OS);

Expand Down
53 changes: 31 additions & 22 deletions lib/IDE/IDETypeChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,9 @@ class ExpressionTypeCollector: public SourceEntityWalker {
// these protocols.
llvm::MapVector<ProtocolDecl*, StringRef> &InterestedProtocols;

// Specified by the client whether we should print fully qualified types
const bool FullyQualified;

// Specified by the client whether we should canonicalize types before printing
const bool CanonicalType;

Expand Down Expand Up @@ -676,16 +679,15 @@ class ExpressionTypeCollector: public SourceEntityWalker {


public:
ExpressionTypeCollector(SourceFile &SF,
llvm::MapVector<ProtocolDecl*, StringRef> &InterestedProtocols,
std::vector<ExpressionTypeInfo> &Results,
bool CanonicalType,
llvm::raw_ostream &OS): Module(*SF.getParentModule()),
SM(SF.getASTContext().SourceMgr),
BufferId(*SF.getBufferID()),
Results(Results), OS(OS),
InterestedProtocols(InterestedProtocols),
CanonicalType(CanonicalType) {}
ExpressionTypeCollector(
SourceFile &SF,
llvm::MapVector<ProtocolDecl *, StringRef> &InterestedProtocols,
std::vector<ExpressionTypeInfo> &Results, bool FullyQualified,
bool CanonicalType, llvm::raw_ostream &OS)
: Module(*SF.getParentModule()), SM(SF.getASTContext().SourceMgr),
BufferId(*SF.getBufferID()), Results(Results), OS(OS),
InterestedProtocols(InterestedProtocols),
FullyQualified(FullyQualified), CanonicalType(CanonicalType) {}
bool walkToExprPre(Expr *E) override {
if (E->getSourceRange().isInvalid())
return true;
Expand All @@ -701,10 +703,12 @@ class ExpressionTypeCollector: public SourceEntityWalker {
{
llvm::raw_svector_ostream OS(Buffer);
auto Ty = E->getType()->getRValueType();
PrintOptions printOptions = PrintOptions();
printOptions.FullyQualifiedTypes = FullyQualified;
if (CanonicalType) {
Ty->getCanonicalType()->print(OS);
Ty->getCanonicalType()->print(OS, printOptions);
} else {
Ty->reconstituteSugar(true)->print(OS);
Ty->reconstituteSugar(true)->print(OS, printOptions);
}
}
auto Ty = getTypeOffsets(Buffer.str());
Expand All @@ -729,12 +733,10 @@ ProtocolDecl* swift::resolveProtocolName(DeclContext *dc, StringRef name) {
nullptr);
}

ArrayRef<ExpressionTypeInfo>
swift::collectExpressionType(SourceFile &SF,
ArrayRef<const char *> ExpectedProtocols,
std::vector<ExpressionTypeInfo> &Scratch,
bool CanonicalType,
llvm::raw_ostream &OS) {
ArrayRef<ExpressionTypeInfo> swift::collectExpressionType(
SourceFile &SF, ArrayRef<const char *> ExpectedProtocols,
std::vector<ExpressionTypeInfo> &Scratch, bool FullyQualified,
bool CanonicalType, llvm::raw_ostream &OS) {
llvm::MapVector<ProtocolDecl*, StringRef> InterestedProtocols;
for (auto Name: ExpectedProtocols) {
if (auto *pd = resolveProtocolName(&SF, Name)) {
Expand All @@ -744,7 +746,7 @@ swift::collectExpressionType(SourceFile &SF,
}
}
ExpressionTypeCollector Walker(SF, InterestedProtocols, Scratch,
CanonicalType, OS);
FullyQualified, CanonicalType, OS);
Walker.walk(SF);
return Scratch;
}
Expand All @@ -759,6 +761,9 @@ class VariableTypeCollector : public SourceEntityWalker {
/// The range in which variable types are to be collected.
SourceRange TotalRange;

// Specified by the client whether we should print fully qualified types
const bool FullyQualified;

/// The output vector for VariableTypeInfos emitted during traversal.
std::vector<VariableTypeInfo> &Results;

Expand Down Expand Up @@ -791,10 +796,12 @@ class VariableTypeCollector : public SourceEntityWalker {

public:
VariableTypeCollector(const SourceFile &SF, SourceRange Range,
bool FullyQualified,
std::vector<VariableTypeInfo> &Results,
llvm::raw_ostream &OS)
: SM(SF.getASTContext().SourceMgr), BufferId(*SF.getBufferID()),
TotalRange(Range), Results(Results), OS(OS) {}
TotalRange(Range), FullyQualified(FullyQualified), Results(Results),
OS(OS) {}

bool walkToDeclPre(Decl *D, CharSourceRange DeclNameRange) override {
if (DeclNameRange.isInvalid()) {
Expand All @@ -814,6 +821,7 @@ class VariableTypeCollector : public SourceEntityWalker {
llvm::raw_svector_ostream OS(Buffer);
PrintOptions Options;
Options.SynthesizeSugarOnTypes = true;
Options.FullyQualifiedTypes = FullyQualified;
auto Ty = VD->getType();
// Skip this declaration and its children if the type is an error type.
if (Ty->is<ErrorType>()) {
Expand Down Expand Up @@ -854,9 +862,10 @@ VariableTypeInfo::VariableTypeInfo(uint32_t Offset, uint32_t Length,
TypeOffset(TypeOffset) {}

void swift::collectVariableType(
SourceFile &SF, SourceRange Range,
SourceFile &SF, SourceRange Range, bool FullyQualified,
std::vector<VariableTypeInfo> &VariableTypeInfos, llvm::raw_ostream &OS) {
VariableTypeCollector Walker(SF, Range, VariableTypeInfos, OS);
VariableTypeCollector Walker(SF, Range, FullyQualified, VariableTypeInfos,
OS);
Walker.walk(SF);
}

Expand Down
13 changes: 13 additions & 0 deletions test/IDE/expr_type_qualified.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: %target-swift-ide-test -print-expr-type -fully-qualified-types -source-filename %S/Inputs/ExprType.swift -swift-version 5 | %FileCheck %s -check-prefix=CHECK-SUGAR
// RUN: %target-swift-ide-test -print-expr-type -fully-qualified-types -source-filename %S/Inputs/ExprType.swift -swift-version 5 -canonicalize-type | %FileCheck %s -check-prefix=CHECK-CANON

// CHECK-SUGAR: func foo() -> Int { return <expr type:"Swift.Int">1</expr> }
// CHECK-SUGAR: func bar(f: Float) -> Float { return <expr type:"Swift.Float"><expr type:"(Swift.Float) -> Swift.Float">bar</expr>(f: <expr type:"Swift.Float">1</expr>)</expr> }
// CHECK-SUGAR: func fooP(_ p: P) { <expr type:"()"><expr type:"(swift_ide_test.P) -> ()">fooP</expr>(<expr type:"swift_ide_test.P">p</expr>)</expr> }
// CHECK-SUGAR: <expr type:"()"><expr type:"Swift.Int">_</expr> = <expr type:"Swift.Int"><expr type:"[swift_ide_test.C]">a</expr>.count</expr></expr>
// CHECK-SUGAR: <expr type:"()"><expr type:"Swift.String">_</expr> = <expr type:"Swift.String"><expr type:"Swift.Int"><expr type:"(Swift.Int) -> Swift.Int"><expr type:"Swift.Int"><expr type:"Swift.String"><expr type:"[swift_ide_test.C]">a</expr>.description</expr>.count</expr>.<expr type:"(Swift.Int) -> (Swift.Int) -> Swift.Int">advanced</expr></expr>(by: <expr type:"Swift.Int">1</expr>)</expr>.description</expr></expr>
// CHECK-SUGAR: <expr type:"()"><expr type:"Swift.Int?">_</expr> = <expr type:"Swift.Int?"><expr type:"Swift.Int"><expr type:"(Swift.Int) -> Swift.Int"><expr type:"Swift.Int"><expr type:"swift_ide_test.S"><expr type:"swift_ide_test.S?"><expr type:"[Swift.Int : swift_ide_test.S]">a</expr>[<expr type:"Swift.Int">2</expr>]</expr>?</expr>.val</expr>.<expr type:"(Swift.Int) -> (Swift.Int) -> Swift.Int">advanced</expr></expr>(by: <expr type:"Swift.Int">1</expr>)</expr>.byteSwapped</expr></expr>


// CHECK-SUGAR: return <expr type:"swift_ide_test.MyInt"><expr type:"swift_ide_test.MyInt">a</expr> <expr type:"(Swift.Int, Swift.Int) -> Swift.Int">+</expr> <expr type:"swift_ide_test.MyInt">b</expr></expr>
// CHECK-CANON: return <expr type:"Swift.Int"><expr type:"Swift.Int">a</expr> <expr type:"(Swift.Int, Swift.Int) -> Swift.Int">+</expr> <expr type:"Swift.Int">b</expr></expr>
13 changes: 13 additions & 0 deletions test/SourceKit/VariableType/basic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,16 @@ let `else` = 3
// CHECK: (15:7, 15:8): (Int) -> Int (explicit type: 1)
// CHECK: (19:7, 19:12): Int (explicit type: 0)
// CHECK: (22:5, 22:11): Int (explicit type: 0)

// RUN: %sourcekitd-test -req=collect-var-type -req-opts=fully_qualified=true %s -- %s | %FileCheck %s --check-prefix CHECK-FULLY-QUALIFIED
// CHECK-FULLY-QUALIFIED: (1:5, 1:6): Swift.Int (explicit type: 1)
// CHECK-FULLY-QUALIFIED: (2:5, 2:6): Swift.String (explicit type: 0)
// CHECK-FULLY-QUALIFIED: (4:5, 4:8): [Swift.String] (explicit type: 0)
// CHECK-FULLY-QUALIFIED: (7:7, 7:8): Swift.String (explicit type: 1)
// CHECK-FULLY-QUALIFIED: (8:7, 8:8): Swift.String (explicit type: 0)
// CHECK-FULLY-QUALIFIED: (12:7, 12:8): Swift.Double (explicit type: 0)
// CHECK-FULLY-QUALIFIED: (13:7, 13:8): [basic.A] (explicit type: 0)
// CHECK-FULLY-QUALIFIED: (14:7, 14:8): [Swift.Int : Swift.Int] (explicit type: 1)
// CHECK-FULLY-QUALIFIED: (15:7, 15:8): (Swift.Int) -> Swift.Int (explicit type: 1)
// CHECK-FULLY-QUALIFIED: (19:7, 19:12): Swift.Int (explicit type: 0)
// CHECK-FULLY-QUALIFIED: (22:5, 22:11): Swift.Int (explicit type: 0)
32 changes: 17 additions & 15 deletions tools/SourceKit/docs/Protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -751,14 +751,15 @@ type checking and the necessary compiler arguments to help resolve all dependenc

```
{
<key.request>: (UID) <source.request.expression.type>,
<key.sourcefile>: (string) // Absolute path to the file.
<key.compilerargs>: [string*] // Array of zero or more strings for the compiler arguments,
// e.g ["-sdk", "/path/to/sdk"]. If key.sourcefile is provided,
// these must include the path to that file.
<key.expectedtypes>: [string*] // A list of interested protocol USRs.
// When empty, we report all expressions in the file.
// When non-empty, we report expressions whose types conform to any of the give protocols.
<key.request>: (UID) <source.request.expression.type>,
<key.sourcefile>: (string) // Absolute path to the file.
<key.compilerargs>: [string*] // Array of zero or more strings for the compiler arguments,
// e.g ["-sdk", "/path/to/sdk"]. If key.sourcefile is provided,
// these must include the path to that file.
<key.expectedtypes>: [string*] // A list of interested protocol USRs.
// When empty, we report all expressions in the file.
// When non-empty, we report expressions whose types conform to any of the give protocols.
[opt] <key.fully_qualified>: (bool) // True when fully qualified type should be returned. Defaults to False.
}
```

Expand Down Expand Up @@ -795,13 +796,14 @@ type checking and the necessary compiler arguments to help resolve all dependenc

```
{
<key.request>: (UID) <source.request.variable.type>,
<key.sourcefile>: (string) // Absolute path to the file.
<key.compilerargs>: [string*] // Array of zero or more strings for the compiler arguments,
// e.g ["-sdk", "/path/to/sdk"]. If key.sourcefile is provided,
// these must include the path to that file.
[opt] <key.offset>: (int64) // Offset of the requested range. Defaults to zero.
[opt] <key.length>: (int64) // Length of the requested range. Defaults to the entire file.
<key.request>: (UID) <source.request.variable.type>,
<key.sourcefile>: (string) // Absolute path to the file.
<key.compilerargs>: [string*] // Array of zero or more strings for the compiler arguments,
// e.g ["-sdk", "/path/to/sdk"]. If key.sourcefile is provided,
// these must include the path to that file.
[opt] <key.offset>: (int64) // Offset of the requested range. Defaults to zero.
[opt] <key.length>: (int64) // Length of the requested range. Defaults to the entire file.
[opt] <key.fully_qualified>: (bool) // True when fully qualified type should be returned. Defaults to False.
}
```

Expand Down
6 changes: 3 additions & 3 deletions tools/SourceKit/include/SourceKit/Core/LangSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -911,8 +911,8 @@ class LangSupport {

virtual void collectExpressionTypes(
StringRef FileName, ArrayRef<const char *> Args,
ArrayRef<const char *> ExpectedProtocols, bool CanonicalType,
SourceKitCancellationToken CancellationToken,
ArrayRef<const char *> ExpectedProtocols, bool FullyQualified,
bool CanonicalType, SourceKitCancellationToken CancellationToken,
std::function<void(const RequestResult<ExpressionTypesInFile> &)>
Receiver) = 0;

Expand All @@ -921,7 +921,7 @@ class LangSupport {
/// the entire document are collected.
virtual void collectVariableTypes(
StringRef FileName, ArrayRef<const char *> Args,
Optional<unsigned> Offset, Optional<unsigned> Length,
Optional<unsigned> Offset, Optional<unsigned> Length, bool FullyQualified,
SourceKitCancellationToken CancellationToken,
std::function<void(const RequestResult<VariableTypesInFile> &)>
Receiver) = 0;
Expand Down
6 changes: 3 additions & 3 deletions tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -686,14 +686,14 @@ class SwiftLangSupport : public LangSupport {

void collectExpressionTypes(
StringRef FileName, ArrayRef<const char *> Args,
ArrayRef<const char *> ExpectedProtocols, bool CanonicalType,
SourceKitCancellationToken CancellationToken,
ArrayRef<const char *> ExpectedProtocols, bool FullyQualified,
bool CanonicalType, SourceKitCancellationToken CancellationToken,
std::function<void(const RequestResult<ExpressionTypesInFile> &)>
Receiver) override;

void collectVariableTypes(
StringRef FileName, ArrayRef<const char *> Args,
Optional<unsigned> Offset, Optional<unsigned> Length,
Optional<unsigned> Offset, Optional<unsigned> Length, bool FullyQualified,
SourceKitCancellationToken CancellationToken,
std::function<void(const RequestResult<VariableTypesInFile> &)> Receiver)
override;
Expand Down
40 changes: 23 additions & 17 deletions tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2526,8 +2526,8 @@ void SwiftLangSupport::semanticRefactoring(

void SwiftLangSupport::collectExpressionTypes(
StringRef FileName, ArrayRef<const char *> Args,
ArrayRef<const char *> ExpectedProtocols, bool CanonicalType,
SourceKitCancellationToken CancellationToken,
ArrayRef<const char *> ExpectedProtocols, bool FullyQualified,
bool CanonicalType, SourceKitCancellationToken CancellationToken,
std::function<void(const RequestResult<ExpressionTypesInFile> &)>
Receiver) {
std::string Error;
Expand All @@ -2542,23 +2542,26 @@ void SwiftLangSupport::collectExpressionTypes(
class ExpressionTypeCollector: public SwiftASTConsumer {
std::function<void(const RequestResult<ExpressionTypesInFile> &)> Receiver;
std::vector<const char *> ExpectedProtocols;
bool FullyQualified;
bool CanonicalType;
public:
ExpressionTypeCollector(
std::function<void(const RequestResult<ExpressionTypesInFile> &)> Receiver,
ArrayRef<const char *> ExpectedProtocols,
bool CanonicalType):
Receiver(std::move(Receiver)),
std::function<void(const RequestResult<ExpressionTypesInFile> &)>
Receiver,
ArrayRef<const char *> ExpectedProtocols, bool FullyQualified,
bool CanonicalType)
: Receiver(std::move(Receiver)),
ExpectedProtocols(ExpectedProtocols.vec()),
CanonicalType(CanonicalType) {}
FullyQualified(FullyQualified), CanonicalType(CanonicalType) {}
void handlePrimaryAST(ASTUnitRef AstUnit) override {
auto *SF = AstUnit->getCompilerInstance().getPrimarySourceFile();
std::vector<ExpressionTypeInfo> Scratch;
llvm::SmallString<256> TypeBuffer;
llvm::raw_svector_ostream OS(TypeBuffer);
ExpressionTypesInFile Result;
for (auto Item: collectExpressionType(*SF, ExpectedProtocols, Scratch,
CanonicalType, OS)) {
for (auto Item :
collectExpressionType(*SF, ExpectedProtocols, Scratch,
FullyQualified, CanonicalType, OS)) {
Result.Results.push_back({Item.offset, Item.length, Item.typeOffset, {}});
for (auto P: Item.protocols) {
Result.Results.back().ProtocolOffsets.push_back(P.first);
Expand All @@ -2576,9 +2579,8 @@ void SwiftLangSupport::collectExpressionTypes(
Receiver(RequestResult<ExpressionTypesInFile>::fromError(Error));
}
};
auto Collector = std::make_shared<ExpressionTypeCollector>(Receiver,
ExpectedProtocols,
CanonicalType);
auto Collector = std::make_shared<ExpressionTypeCollector>(
Receiver, ExpectedProtocols, FullyQualified, CanonicalType);
/// FIXME: When request cancellation is implemented and Xcode adopts it,
/// don't use 'OncePerASTToken'.
static const char OncePerASTToken = 0;
Expand All @@ -2589,7 +2591,8 @@ void SwiftLangSupport::collectExpressionTypes(

void SwiftLangSupport::collectVariableTypes(
StringRef FileName, ArrayRef<const char *> Args, Optional<unsigned> Offset,
Optional<unsigned> Length, SourceKitCancellationToken CancellationToken,
Optional<unsigned> Length, bool FullyQualified,
SourceKitCancellationToken CancellationToken,
std::function<void(const RequestResult<VariableTypesInFile> &)> Receiver) {
std::string Error;
SwiftInvocationRef Invok =
Expand All @@ -2606,13 +2609,16 @@ void SwiftLangSupport::collectVariableTypes(
std::function<void(const RequestResult<VariableTypesInFile> &)> Receiver;
Optional<unsigned> Offset;
Optional<unsigned> Length;
bool FullyQualified;

public:
VariableTypeCollectorASTConsumer(
std::function<void(const RequestResult<VariableTypesInFile> &)>
Receiver,
Optional<unsigned> Offset, Optional<unsigned> Length)
: Receiver(std::move(Receiver)), Offset(Offset), Length(Length) {}
Optional<unsigned> Offset, Optional<unsigned> Length,
bool FullyQualified)
: Receiver(std::move(Receiver)), Offset(Offset), Length(Length),
FullyQualified(FullyQualified) {}

void handlePrimaryAST(ASTUnitRef AstUnit) override {
auto &CompInst = AstUnit->getCompilerInstance();
Expand All @@ -2636,7 +2642,7 @@ void SwiftLangSupport::collectVariableTypes(
llvm::raw_string_ostream OS(TypeBuffer);
VariableTypesInFile Result;

collectVariableType(*SF, Range, Infos, OS);
collectVariableType(*SF, Range, FullyQualified, Infos, OS);

for (auto Info : Infos) {
Result.Results.push_back({Info.Offset, Info.Length, Info.TypeOffset, Info.HasExplicitType});
Expand All @@ -2655,7 +2661,7 @@ void SwiftLangSupport::collectVariableTypes(
};

auto Collector = std::make_shared<VariableTypeCollectorASTConsumer>(
Receiver, Offset, Length);
Receiver, Offset, Length, FullyQualified);
/// FIXME: When request cancellation is implemented and Xcode adopts it,
/// don't use 'OncePerASTToken'.
static const char OncePerASTToken = 0;
Expand Down
Loading