Skip to content

Commit 0ccbfdb

Browse files
authored
Index: Record override-of relationship between a decl in protocol extension and the protocol requirements it can provide default implementations for. (#8418)
1 parent 9964797 commit 0ccbfdb

File tree

6 files changed

+135
-43
lines changed

6 files changed

+135
-43
lines changed

include/swift/Sema/IDETypeChecking.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ namespace swift {
4949
void collectDefaultImplementationForProtocolMembers(ProtocolDecl *PD,
5050
llvm::SmallDenseMap<ValueDecl*, ValueDecl*> &DefaultMap);
5151

52+
/// \brief Collect all the protocol requirements that a given declaration can
53+
/// provide default implementations for. VD is a declaration in extension
54+
/// declaration. Scratch is the buffer to collect those protocol
55+
/// requirements.
56+
///
57+
/// \returns the slice of Scratch
58+
ArrayRef<ValueDecl*> canDeclProvideDefaultImplementationFor(ValueDecl* VD,
59+
llvm::SmallVectorImpl<ValueDecl*> &Scractch);
60+
5261
/// \brief Given an unresolved member E and its parent P, this function tries
5362
/// to infer the type of E.
5463
/// \returns true on success, false on error.

lib/IDE/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ add_swift_library(swiftIDE STATIC
99
SwiftSourceDocInfo.cpp
1010
SyntaxModel.cpp
1111
Utils.cpp
12+
IDETypeChecking.cpp
1213
LINK_LIBRARIES
1314
swiftFrontend
1415
swiftClangImporter

lib/IDE/IDETypeChecking.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//===--- IDETypeChecking.cpp ----------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "swift/AST/ASTContext.h"
14+
#include "swift/AST/Identifier.h"
15+
#include "swift/AST/Decl.h"
16+
#include "swift/AST/Types.h"
17+
#include "swift/Sema/IDETypeChecking.h"
18+
19+
using namespace swift;
20+
21+
ArrayRef<ValueDecl*> swift::
22+
canDeclProvideDefaultImplementationFor(ValueDecl* VD,
23+
llvm::SmallVectorImpl<ValueDecl*> &Scractch) {
24+
25+
// Skip decls that don't have valid names.
26+
if (!VD->getFullName())
27+
return {};
28+
29+
// Check if VD is from a protocol extension.
30+
auto P = VD->getDeclContext()->getAsProtocolExtensionContext();
31+
if (!P)
32+
return {};
33+
34+
// Look up all decls in the protocol's inheritance chain for the ones with
35+
// the same name with VD.
36+
ResolvedMemberResult LookupResult =
37+
resolveValueMember(*P->getInnermostDeclContext(),
38+
P->getDeclaredInterfaceType(), VD->getFullName());
39+
40+
for (auto Mem : LookupResult.getMemberDecls(InterestedMemberKind::All)) {
41+
if (auto Pro = dyn_cast<ProtocolDecl>(Mem->getDeclContext())) {
42+
if (Mem->isProtocolRequirement() &&
43+
Mem->getInterfaceType()->isEqual(VD->getInterfaceType())) {
44+
// We find a protocol requirement VD can provide default
45+
// implementation for.
46+
Scractch.push_back(Mem);
47+
}
48+
}
49+
}
50+
return Scractch;
51+
}
52+
53+
void swift::
54+
collectDefaultImplementationForProtocolMembers(ProtocolDecl *PD,
55+
llvm::SmallDenseMap<ValueDecl*, ValueDecl*> &DefaultMap) {
56+
Type BaseTy = PD->getDeclaredInterfaceType();
57+
DeclContext *DC = PD->getInnermostDeclContext();
58+
auto HandleMembers = [&](DeclRange Members) {
59+
for (Decl *D : Members) {
60+
ValueDecl *VD = dyn_cast<ValueDecl>(D);
61+
62+
// Skip non-value decl.
63+
if (!VD)
64+
continue;
65+
66+
// Skip decls with empty names, e.g. setter/getters for properties.
67+
if (VD->getName().empty())
68+
continue;
69+
70+
ResolvedMemberResult Result = resolveValueMember(*DC, BaseTy,
71+
VD->getFullName());
72+
assert(Result);
73+
for (auto *Default : Result.getMemberDecls(InterestedMemberKind::All)) {
74+
if (PD == Default->getDeclContext()->getAsProtocolExtensionContext()) {
75+
DefaultMap.insert({Default, VD});
76+
}
77+
}
78+
}
79+
};
80+
81+
// Collect the default implementations for the members in this given protocol.
82+
HandleMembers(PD->getMembers());
83+
84+
// Collect the default implementations for the members in the inherited
85+
// protocols.
86+
for (auto* IP : PD->getInheritedProtocols())
87+
HandleMembers(IP->getMembers());
88+
}

lib/Index/Index.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/AST/USRGeneration.h"
2323
#include "swift/Basic/SourceManager.h"
2424
#include "swift/Basic/StringExtras.h"
25+
#include "swift/Sema/IDETypeChecking.h"
2526
#include "llvm/ADT/APInt.h"
2627
#include "llvm/ADT/SmallVector.h"
2728
#include "llvm/Support/ErrorHandling.h"
@@ -596,6 +597,17 @@ bool IndexSwiftASTWalker::startEntityDecl(ValueDecl *D) {
596597
if (addRelation(Info, (SymbolRoleSet) SymbolRole::RelationOverrideOf, Overridden))
597598
return false;
598599
}
600+
601+
{
602+
// Collect the protocol requirements this decl can provide default
603+
// implementations to, and record them as overriding.
604+
llvm::SmallVector<ValueDecl*, 2> Buffer;
605+
for (auto Req : canDeclProvideDefaultImplementationFor(D, Buffer)) {
606+
if (addRelation(Info, (SymbolRoleSet) SymbolRole::RelationOverrideOf, Req))
607+
return false;
608+
}
609+
}
610+
599611
// FIXME: This is quite expensive and not worth the cost for indexing purposes
600612
// of system modules. Revisit if this becomes more efficient.
601613
if (!isSystemModule) {

lib/Sema/TypeChecker.cpp

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,46 +1002,3 @@ TypeChecker::getDeclTypeCheckingSemantics(ValueDecl *decl) {
10021002
}
10031003
return DeclTypeCheckingSemantics::Normal;
10041004
}
1005-
1006-
void swift::
1007-
collectDefaultImplementationForProtocolMembers(ProtocolDecl *PD,
1008-
llvm::SmallDenseMap<ValueDecl*, ValueDecl*> &DefaultMap) {
1009-
Type BaseTy = PD->getDeclaredInterfaceType();
1010-
DeclContext *DC = PD->getInnermostDeclContext();
1011-
std::unique_ptr<TypeChecker> CreatedTC;
1012-
auto *TC = static_cast<TypeChecker*>(DC->getASTContext().getLazyResolver());
1013-
if (!TC) {
1014-
CreatedTC.reset(new TypeChecker(DC->getASTContext()));
1015-
TC = CreatedTC.get();
1016-
}
1017-
auto HandleMembers = [&](DeclRange Members) {
1018-
for (Decl *D : Members) {
1019-
ValueDecl *VD = dyn_cast<ValueDecl>(D);
1020-
1021-
// Skip non-value decl.
1022-
if (!VD)
1023-
continue;
1024-
1025-
// Skip decls with empty names, e.g. setter/getters for properties.
1026-
if (VD->getName().empty())
1027-
continue;
1028-
1029-
ResolvedMemberResult Result = resolveValueMember(*DC, BaseTy,
1030-
VD->getFullName());
1031-
assert(Result);
1032-
for (auto *Default : Result.getMemberDecls(InterestedMemberKind::All)) {
1033-
if (PD == Default->getDeclContext()->getAsProtocolExtensionContext()) {
1034-
DefaultMap.insert({Default, VD});
1035-
}
1036-
}
1037-
}
1038-
};
1039-
1040-
// Collect the default implementations for the members in this given protocol.
1041-
HandleMembers(PD->getMembers());
1042-
1043-
// Collect the default implementations for the members in the inherited
1044-
// protocols.
1045-
for (auto* IP : PD->getInheritedProtocols())
1046-
HandleMembers(IP->getMembers());
1047-
}

test/Index/roles.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,3 +333,28 @@ func containing() {
333333
}
334334
}
335335
}
336+
337+
protocol ProtRoot {
338+
func fooCommon()
339+
func foo1()
340+
func foo2()
341+
}
342+
343+
protocol ProtDerived : ProtRoot {
344+
func fooCommon()
345+
func bar1()
346+
func bar2()
347+
}
348+
349+
extension ProtDerived {
350+
func fooCommon() {}
351+
// CHECK: 350:8 | instance-method/Swift | fooCommon() | s:14swift_ide_test11ProtDerivedPAAE9fooCommonyyF | Def,RelChild,RelOver | rel: 2
352+
// CHECK-NEXT: RelOver | instance-method/Swift | fooCommon() | s:14swift_ide_test11ProtDerivedP9fooCommonyyF
353+
354+
func foo1() {}
355+
// FIXME: This should override foo1 from ProtRoot.
356+
357+
func bar1() {}
358+
// CHECK: 357:8 | instance-method/Swift | bar1() | s:14swift_ide_test11ProtDerivedPAAE4bar1yyF | Def,RelChild,RelOver | rel: 2
359+
// CHECK-NEXT: RelOver | instance-method/Swift | bar1() | s:14swift_ide_test11ProtDerivedP4bar1yyF
360+
}

0 commit comments

Comments
 (0)