Merge pull request #32148 from nathawes/doc-info-underscored-protocol-synthesised-extensions

[IDE][SourceKit/DocSupport] Add members of underscored protocol extensions in extensions of conforming types.
This commit is contained in:
Nathan Hawes
2020-06-10 14:49:18 -07:00
committed by GitHub
15 changed files with 3407 additions and 1345 deletions

View File

@@ -260,7 +260,9 @@ struct SourceTextInfo {
} // end anonymous namespace
static void initDocGenericParams(const Decl *D, DocEntityInfo &Info) {
static void initDocGenericParams(const Decl *D, DocEntityInfo &Info,
TypeOrExtensionDecl SynthesizedTarget,
bool IsSynthesizedExt) {
auto *GC = D->getAsGenericContext();
if (!GC)
return;
@@ -276,36 +278,107 @@ static void initDocGenericParams(const Decl *D, DocEntityInfo &Info) {
if (ParentSig && ParentSig->isEqual(GenericSig))
return;
// If we have a synthesized target, map from its base type into the this
// declaration's innermost type context, or if we're dealing with the
// synthesized extention itself rather than a member, into its extended
// nominal (the extension's own requirements shouldn't be considered in the
// substitution).
SubstitutionMap SubMap;
Type BaseType;
if (SynthesizedTarget) {
BaseType = SynthesizedTarget.getBaseNominal()->getDeclaredInterfaceType();
if (!BaseType->isExistentialType()) {
DeclContext *DC;
if (IsSynthesizedExt)
DC = cast<ExtensionDecl>(D)->getExtendedNominal();
else
DC = D->getInnermostDeclContext()->getInnermostTypeContext();
auto *M = DC->getParentModule();
SubMap = BaseType->getContextSubstitutionMap(M, DC);
}
}
auto SubstTypes = [&](Type Ty) {
return Ty.subst(SubMap, SubstFlags::DesugarMemberTypes);
};
// FIXME: Not right for extensions of nested generic types
if (GC->isGeneric()) {
for (auto *GP : GenericSig->getInnermostGenericParams()) {
if (GP->getDecl()->isImplicit())
continue;
Type TypeToPrint = GP;
if (!SubMap.empty()) {
if (auto ArgTy = SubstTypes(GP)) {
if (!ArgTy->hasError()) {
// Ignore parameter that aren't generic after substitution
if (!ArgTy->is<ArchetypeType>() && !ArgTy->isTypeParameter())
continue;
TypeToPrint = ArgTy;
}
}
}
DocGenericParam Param;
Param.Name = std::string(GP->getName());
Param.Name = TypeToPrint->getString();
Info.GenericParams.push_back(Param);
}
}
ProtocolDecl *proto = nullptr;
ProtocolDecl *Proto = nullptr;
if (auto *typeDC = GC->getInnermostTypeContext())
proto = typeDC->getSelfProtocolDecl();
Proto = typeDC->getSelfProtocolDecl();
for (auto &Req : GenericSig->getRequirements()) {
// Skip protocol Self requirement.
if (proto &&
for (auto Req: GenericSig->getRequirements()) {
if (Proto &&
Req.getKind() == RequirementKind::Conformance &&
Req.getFirstType()->isEqual(proto->getSelfInterfaceType()) &&
Req.getSecondType()->getAnyNominal() == proto)
Req.getFirstType()->isEqual(Proto->getSelfInterfaceType()) &&
Req.getSecondType()->getAnyNominal() == Proto)
continue;
auto First = Req.getFirstType();
Type Second;
if (Req.getKind() != RequirementKind::Layout)
Second = Req.getSecondType();
if (!SubMap.empty()) {
Type SubFirst = SubstTypes(First);
if (!SubFirst->hasError())
First = SubFirst;
if (Second) {
Type SubSecond = SubstTypes(Second);
if (!SubSecond->hasError())
Second = SubSecond;
// Ignore requirements that don't involve a generic after substitution.
if (!(First->is<ArchetypeType>() || First->isTypeParameter()) &&
!(Second->is<ArchetypeType>() || Second->isTypeParameter()))
continue;
}
}
std::string ReqStr;
PrintOptions Opts;
llvm::raw_string_ostream OS(ReqStr);
Req.print(OS, Opts);
PrintOptions Opts;
if (Req.getKind() != RequirementKind::Layout) {
Requirement(Req.getKind(), First, Second).print(OS, Opts);
} else {
Requirement(Req.getKind(), First, Req.getLayoutConstraint()).print(OS, Opts);
}
OS.flush();
Info.GenericRequirements.push_back(std::move(ReqStr));
}
if (IsSynthesizedExt) {
// If there's a conditional conformance on the base type that 'enabled' this
// extension, we need to print its requirements too.
if (auto *EnablingExt = dyn_cast<ExtensionDecl>(SynthesizedTarget.getAsDecl())) {
if (EnablingExt->isConstrainedExtension()) {
initDocGenericParams(EnablingExt, Info,
/*Target=*/EnablingExt->getExtendedNominal(),
/*IsSynthesizedExtension*/false);
}
}
}
}
static bool initDocEntityInfo(const Decl *D,
@@ -376,29 +449,12 @@ static bool initDocEntityInfo(const Decl *D,
llvm::SmallString<128> DocBuffer;
{
llvm::raw_svector_ostream OSS(DocBuffer);
ide::getDocumentationCommentAsXML(D, OSS);
ide::getDocumentationCommentAsXML(D, OSS, SynthesizedTarget);
}
StringRef DocRef = (StringRef)DocBuffer;
if (IsSynthesizedExtension &&
DocRef.find("<Declaration>") != StringRef::npos) {
StringRef Open = "extension ";
assert(DocRef.find(Open) != StringRef::npos);
auto FirstPart = DocRef.substr(0, DocRef.find(Open) + (Open).size());
auto SecondPart = DocRef.substr(FirstPart.size());
auto ExtendedName = ((const ExtensionDecl*)D)->getExtendedNominal()
->getName().str();
assert(SecondPart.startswith(ExtendedName));
SecondPart = SecondPart.substr(ExtendedName.size());
llvm::SmallString<128> UpdatedDocBuffer;
UpdatedDocBuffer.append(FirstPart);
UpdatedDocBuffer.append(SynthesizedTargetNTD->getName().str());
UpdatedDocBuffer.append(SecondPart);
OS << UpdatedDocBuffer;
} else
OS << DocBuffer;
OS << DocBuffer;
}
initDocGenericParams(D, Info);
initDocGenericParams(D, Info, SynthesizedTarget, IsSynthesizedExtension);
llvm::raw_svector_ostream LocalizationKeyOS(Info.LocalizationKey);
ide::getLocalizationKey(D, LocalizationKeyOS);
@@ -410,14 +466,13 @@ static bool initDocEntityInfo(const Decl *D,
VD, SynthesizedTarget, OS);
else
SwiftLangSupport::printFullyAnnotatedDeclaration(VD, Type(), OS);
} else if (auto *E = dyn_cast<ExtensionDecl>(D)) {
if (auto Sig = E->getGenericSignature()) {
// The extension under printing is potentially part of a synthesized
// extension. Thus it's hard to print the fully annotated decl. We
// need to at least print the generic signature here.
llvm::raw_svector_ostream OS(Info.FullyAnnotatedGenericSig);
SwiftLangSupport::printFullyAnnotatedGenericReq(Sig, OS);
}
} else if (auto *ED = dyn_cast<ExtensionDecl>(D)) {
llvm::raw_svector_ostream OS(Info.FullyAnnotatedDecl);
if (SynthesizedTarget)
SwiftLangSupport::printFullyAnnotatedSynthesizedDeclaration(
ED, SynthesizedTarget, OS);
else
SwiftLangSupport::printFullyAnnotatedDeclaration(ED, OS);
}
if (DeclaringModForCrossImport) {