1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "RefactoringActions.h"
#include "swift/AST/ProtocolConformance.h"
using namespace swift::refactoring;
namespace {
/// The helper class analyzes a given nominal decl or an extension decl to
/// decide whether stubs are required to filled in and the context in which
/// these stubs should be filled.
class FillProtocolStubContext {
std::vector<ValueDecl *>
getUnsatisfiedRequirements(const IterableDeclContext *IDC);
/// Context in which the content should be filled; this could be either a
/// nominal type declaraion or an extension declaration.
DeclContext *DC;
/// The type that adopts the required protocol stubs. For nominal type decl,
/// this should be the declared type itself; for extension decl, this should
/// be the extended type at hand.
Type Adopter;
/// The start location of the decl, either nominal type or extension, for the
/// printer to figure out the right indentation.
SourceLoc StartLoc;
/// The location of '{' for the decl, thus we know where to insert the filling
/// stubs.
SourceLoc BraceStartLoc;
/// The value decls that should be satisfied; this could be either function
/// decls, property decls, or required type alias.
std::vector<ValueDecl *> FillingContents;
public:
FillProtocolStubContext(ExtensionDecl *ED)
: DC(ED), Adopter(ED->getExtendedType()), StartLoc(ED->getStartLoc()),
BraceStartLoc(ED->getBraces().Start),
FillingContents(getUnsatisfiedRequirements(ED)){};
FillProtocolStubContext(NominalTypeDecl *ND)
: DC(ND), Adopter(ND->getDeclaredType()), StartLoc(ND->getStartLoc()),
BraceStartLoc(ND->getBraces().Start),
FillingContents(getUnsatisfiedRequirements(ND)){};
FillProtocolStubContext() : DC(nullptr), Adopter(), FillingContents({}){};
static FillProtocolStubContext
getContextFromCursorInfo(ResolvedCursorInfoPtr Tok);
ArrayRef<ValueDecl *> getFillingContents() const {
return llvm::ArrayRef(FillingContents);
}
DeclContext *getFillingContext() const { return DC; }
bool canProceed() const {
return StartLoc.isValid() && BraceStartLoc.isValid() &&
!getFillingContents().empty();
}
Type getAdopter() const { return Adopter; }
SourceLoc getContextStartLoc() const { return StartLoc; }
SourceLoc getBraceStartLoc() const { return BraceStartLoc; }
};
FillProtocolStubContext FillProtocolStubContext::getContextFromCursorInfo(
ResolvedCursorInfoPtr CursorInfo) {
if (!CursorInfo->isValid())
return FillProtocolStubContext();
auto ValueRefInfo = dyn_cast<ResolvedValueRefCursorInfo>(CursorInfo);
if (!ValueRefInfo) {
return FillProtocolStubContext();
}
if (!ValueRefInfo->isRef()) {
// If the type name is on the declared nominal, e.g. "class A {}"
if (auto ND = dyn_cast<NominalTypeDecl>(ValueRefInfo->getValueD())) {
return FillProtocolStubContext(ND);
}
} else if (auto *ED = ValueRefInfo->getExtTyRef()) {
// If the type ref is on a declared extension, e.g. "extension A {}"
return FillProtocolStubContext(ED);
}
return FillProtocolStubContext();
}
} // namespace
std::vector<ValueDecl *> FillProtocolStubContext::getUnsatisfiedRequirements(
const IterableDeclContext *IDC) {
// The results to return.
std::vector<ValueDecl *> NonWitnessedReqs;
// For each conformance of the extended nominal.
for (ProtocolConformance *Con : IDC->getLocalConformances()) {
// Collect non-witnessed requirements.
Con->forEachNonWitnessedRequirement(
[&](ValueDecl *VD) { NonWitnessedReqs.push_back(VD); });
}
return NonWitnessedReqs;
}
bool RefactoringActionFillProtocolStub::isApplicable(ResolvedCursorInfoPtr Tok,
DiagnosticEngine &Diag) {
return FillProtocolStubContext::getContextFromCursorInfo(Tok).canProceed();
}
bool RefactoringActionFillProtocolStub::performChange() {
// Get the filling protocol context from the input token.
FillProtocolStubContext Context =
FillProtocolStubContext::getContextFromCursorInfo(CursorInfo);
assert(Context.canProceed());
assert(!Context.getFillingContents().empty());
assert(Context.getFillingContext());
SmallString<128> Text;
{
llvm::raw_svector_ostream SS(Text);
Type Adopter = Context.getAdopter();
SourceLoc Loc = Context.getContextStartLoc();
auto Contents = Context.getFillingContents();
// For each unsatisfied requirement, print the stub to the buffer.
std::for_each(Contents.begin(), Contents.end(), [&](ValueDecl *VD) {
printRequirementStub(VD, Context.getFillingContext(), Adopter, Loc, SS);
});
}
// Insert all stubs after '{' in the extension/nominal type decl.
EditConsumer.insertAfter(SM, Context.getBraceStartLoc(), Text);
return false;
}
|