Files
swift-mirror/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp
Robert Widmann 5a8d0744c3 [NFC] Adopt TypeBase-isms for GenericSignature
Structurally prevent a number of common anti-patterns involving generic
signatures by separating the interface into GenericSignature and the
implementation into GenericSignatureBase.  In particular, this allows
the comparison operators to be deleted which forces callers to
canonicalize the signature or ask to compare pointers explicitly.
2019-09-30 14:04:36 -07:00

1482 lines
51 KiB
C++

//===--- SwiftDocSupport.cpp ----------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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 "clang/AST/Decl.h"
#include "clang/Basic/Module.h"
#include "SwiftASTManager.h"
#include "SwiftEditorDiagConsumer.h"
#include "SwiftLangSupport.h"
#include "SourceKit/Support/Logging.h"
#include "SourceKit/Support/UIdent.h"
#include "swift/AST/ASTPrinter.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/TypeRepr.h"
#include "swift/Frontend/Frontend.h"
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
#include "swift/IDE/CommentConversion.h"
#include "swift/IDE/ModuleInterfacePrinting.h"
#include "swift/IDE/SourceEntityWalker.h"
#include "swift/IDE/SyntaxModel.h"
#include "swift/IDE/Refactoring.h"
// This is included only for createLazyResolver(). Move to different header ?
#include "swift/Sema/IDETypeChecking.h"
#include "swift/Config.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
using namespace SourceKit;
using namespace swift;
using namespace ide;
static ModuleDecl *getModuleByFullName(ASTContext &Ctx, StringRef ModuleName) {
SmallVector<std::pair<Identifier, SourceLoc>, 4>
AccessPath;
while (!ModuleName.empty()) {
StringRef SubModuleName;
std::tie(SubModuleName, ModuleName) = ModuleName.split('.');
AccessPath.push_back({ Ctx.getIdentifier(SubModuleName), SourceLoc() });
}
return Ctx.getModule(AccessPath);
}
static ModuleDecl *getModuleByFullName(ASTContext &Ctx, Identifier ModuleName) {
return Ctx.getModule(std::make_pair(ModuleName, SourceLoc()));
}
namespace {
struct TextRange {
unsigned Offset;
unsigned Length;
};
struct TextEntity {
const Decl *Dcl = nullptr;
TypeOrExtensionDecl SynthesizeTarget;
const Decl *DefaultImplementationOf = nullptr;
StringRef Argument;
TextRange Range;
unsigned LocOffset = 0;
std::vector<TextEntity> SubEntities;
const bool IsSynthesizedExtension;
TextEntity(const Decl *D, TypeOrExtensionDecl SynthesizeTarget,
const Decl *DefaultImplementationOf, unsigned StartOffset,
bool IsSynthesizedExtension)
: Dcl(D), SynthesizeTarget(SynthesizeTarget),
DefaultImplementationOf(DefaultImplementationOf), Range{StartOffset, 0},
IsSynthesizedExtension(IsSynthesizedExtension) {}
TextEntity(const Decl *D, TypeOrExtensionDecl SynthesizeTarget,
const Decl *DefaultImplementationOf, TextRange TR,
unsigned LocOffset, bool IsSynthesizedExtension)
: Dcl(D), DefaultImplementationOf(DefaultImplementationOf), Range(TR),
LocOffset(LocOffset), IsSynthesizedExtension(IsSynthesizedExtension) {}
TextEntity(const Decl *D, TypeOrExtensionDecl SynthesizeTarget,
const Decl *DefaultImplementationOf, StringRef Arg, TextRange TR,
unsigned LocOffset, bool IsSynthesizedExtension)
: Dcl(D), SynthesizeTarget(SynthesizeTarget),
DefaultImplementationOf(DefaultImplementationOf), Argument(Arg),
Range(TR), LocOffset(LocOffset),
IsSynthesizedExtension(IsSynthesizedExtension) {}
};
struct TextReference {
const ValueDecl *Dcl = nullptr;
TextRange Range;
const Type Ty;
TextReference(const ValueDecl *D, unsigned Offset, unsigned Length,
const Type Ty = Type()) : Dcl(D), Range{Offset, Length}, Ty(Ty) {}
};
class AnnotatingPrinter : public StreamPrinter {
std::pair<const ExtensionDecl *, TypeOrExtensionDecl>
SynthesizedExtensionInfo = {nullptr, {}};
typedef llvm::SmallDenseMap<ValueDecl*, ValueDecl*> DefaultImplementMap;
llvm::SmallDenseMap<ProtocolDecl*, DefaultImplementMap> AllDefaultMaps;
DefaultImplementMap *DefaultMapToUse = nullptr;
void initDefaultMapToUse(const Decl *D) {
const auto *ED = dyn_cast<ExtensionDecl>(D);
if (!ED)
return;
if (auto NTD = ED->getExtendedNominal()) {
if (auto *PD = dyn_cast<ProtocolDecl>(NTD)) {
auto Pair = AllDefaultMaps.insert({PD, DefaultImplementMap()});
DefaultMapToUse = &Pair.first->getSecond();
if (Pair.second) {
swift::collectDefaultImplementationForProtocolMembers(PD,
Pair.first->getSecond());
}
}
}
}
void deinitDefaultMapToUse(const Decl*D) {
if (isa<ExtensionDecl>(D)) {
DefaultMapToUse = nullptr;
}
}
ValueDecl *getDefaultImplementation(const Decl *D) {
if (!DefaultMapToUse)
return nullptr;
auto *VD = const_cast<ValueDecl*>(dyn_cast<ValueDecl>(D));
auto Found = DefaultMapToUse->find(VD);
if (Found != DefaultMapToUse->end()) {
return Found->second;
}
return nullptr;
}
public:
std::vector<TextEntity> TopEntities;
std::vector<TextEntity> EntitiesStack;
std::vector<TextReference> References;
using StreamPrinter::StreamPrinter;
~AnnotatingPrinter() override {
assert(EntitiesStack.empty());
}
bool shouldContinuePre(const Decl *D, Optional<BracketOptions> Bracket) {
assert(Bracket.hasValue());
if (!Bracket.getValue().shouldOpenExtension(D) &&
isa<ExtensionDecl>(D))
return false;
return true;
}
bool shouldContinuePost(const Decl *D, Optional<BracketOptions> Bracket) {
assert(Bracket.hasValue());
if (!Bracket.getValue().shouldCloseNominal(D) && isa<NominalTypeDecl>(D))
return false;
if (!Bracket.getValue().shouldCloseExtension(D) &&
isa<ExtensionDecl>(D))
return false;
return true;
}
void printSynthesizedExtensionPre(const ExtensionDecl *ED,
TypeOrExtensionDecl Target,
Optional<BracketOptions> Bracket) override {
assert(!SynthesizedExtensionInfo.first);
SynthesizedExtensionInfo = {ED, Target};
if (!shouldContinuePre(ED, Bracket))
return;
unsigned StartOffset = OS.tell();
EntitiesStack.emplace_back(ED, Target, nullptr, StartOffset, true);
}
void
printSynthesizedExtensionPost(const ExtensionDecl *ED,
TypeOrExtensionDecl Target,
Optional<BracketOptions> Bracket) override {
assert(SynthesizedExtensionInfo.first);
SynthesizedExtensionInfo = {nullptr, {}};
if (!shouldContinuePost(ED, Bracket))
return;
TextEntity Entity = std::move(EntitiesStack.back());
EntitiesStack.pop_back();
unsigned EndOffset = OS.tell();
Entity.Range.Length = EndOffset - Entity.Range.Offset;
TopEntities.push_back(std::move(Entity));
}
void printDeclPre(const Decl *D, Optional<BracketOptions> Bracket) override {
if (isa<ParamDecl>(D))
return; // Parameters are handled specially in addParameters().
if (!shouldContinuePre(D, Bracket))
return;
unsigned StartOffset = OS.tell();
initDefaultMapToUse(D);
// If D is declared in the extension, then the synthesized target is valid.
TypeOrExtensionDecl SynthesizedTarget;
assert(D->getDeclContext()->isModuleScopeContext() == EntitiesStack.empty());
if (D->getDeclContext() == SynthesizedExtensionInfo.first)
SynthesizedTarget = SynthesizedExtensionInfo.second;
EntitiesStack.emplace_back(D, SynthesizedTarget,
getDefaultImplementation(D), StartOffset, false);
}
void printDeclLoc(const Decl *D) override {
if (EntitiesStack.back().Dcl == D) {
unsigned LocOffset = OS.tell();
EntitiesStack.back().LocOffset = LocOffset;
}
}
void printDeclPost(const Decl *D, Optional<BracketOptions> Bracket) override {
if (isa<ParamDecl>(D))
return; // Parameters are handled specially in addParameters().
if (!shouldContinuePost(D, Bracket))
return;
assert(!EntitiesStack.empty());
TextEntity Entity = std::move(EntitiesStack.back());
EntitiesStack.pop_back();
unsigned EndOffset = OS.tell();
Entity.Range.Length = EndOffset - Entity.Range.Offset;
if (EntitiesStack.empty()) {
assert (D->getDeclContext()->isModuleScopeContext());
TopEntities.push_back(std::move(Entity));
} else {
assert (!D->getDeclContext()->isModuleScopeContext());
EntitiesStack.back().SubEntities.push_back(std::move(Entity));
}
deinitDefaultMapToUse(D);
}
void printTypeRef(
Type T, const TypeDecl *TD, Identifier Name,
PrintNameContext NameContext = PrintNameContext::Normal) override {
unsigned StartOffset = OS.tell();
References.emplace_back(TD, StartOffset, Name.str().size());
StreamPrinter::printTypeRef(T, TD, Name, NameContext);
}
};
struct SourceTextInfo {
std::string Text;
std::vector<TextEntity> TopEntities;
std::vector<TextReference> References;
};
} // end anonymous namespace
static void initDocGenericParams(const Decl *D, DocEntityInfo &Info) {
auto *DC = dyn_cast<DeclContext>(D);
if (DC == nullptr || !DC->isInnermostContextGeneric())
return;
GenericSignature GenericSig = DC->getGenericSignatureOfContext();
if (!GenericSig)
return;
// FIXME: Not right for extensions of nested generic types
for (auto *GP : GenericSig->getInnermostGenericParams()) {
if (GP->getDecl()->isImplicit())
continue;
DocGenericParam Param;
Param.Name = GP->getName().str();
Info.GenericParams.push_back(Param);
}
ProtocolDecl *proto = nullptr;
if (auto *typeDC = DC->getInnermostTypeContext())
proto = typeDC->getSelfProtocolDecl();
for (auto &Req : GenericSig->getRequirements()) {
// Skip protocol Self requirement.
if (proto &&
Req.getKind() == RequirementKind::Conformance &&
Req.getFirstType()->isEqual(proto->getSelfInterfaceType()) &&
Req.getSecondType()->getAnyNominal() == proto)
continue;
std::string ReqStr;
PrintOptions Opts;
llvm::raw_string_ostream OS(ReqStr);
Req.print(OS, Opts);
OS.flush();
Info.GenericRequirements.push_back(std::move(ReqStr));
}
}
static bool initDocEntityInfo(const Decl *D,
TypeOrExtensionDecl SynthesizedTarget,
const Decl *DefaultImplementationOf, bool IsRef,
bool IsSynthesizedExtension, DocEntityInfo &Info,
StringRef Arg = StringRef()) {
if (!IsRef && D->isImplicit())
return true;
if (!D || isa<ParamDecl>(D) ||
(isa<VarDecl>(D) && D->getDeclContext()->isLocalContext())) {
Info.Kind = SwiftLangSupport::getUIDForLocalVar(IsRef);
if (D) {
llvm::raw_svector_ostream OS(Info.Name);
SwiftLangSupport::printDisplayName(cast<ValueDecl>(D), OS);
} else {
Info.Name = "_";
}
if (!Arg.empty())
Info.Argument = Arg.str();
return false;
}
auto SynthesizedTargetNTD =
SynthesizedTarget ? SynthesizedTarget.getBaseNominal() : nullptr;
if (IsSynthesizedExtension) {
Info.Kind =
SwiftLangSupport::getUIDForExtensionOfDecl(SynthesizedTargetNTD);
} else
Info.Kind = SwiftLangSupport::getUIDForDecl(D, IsRef);
if (Info.Kind.isInvalid())
return true;
if (const auto *VD = dyn_cast<ValueDecl>(D)) {
llvm::raw_svector_ostream NameOS(Info.Name);
SwiftLangSupport::printDisplayName(VD, NameOS);
{
llvm::raw_svector_ostream OS(Info.USR);
SwiftLangSupport::printUSR(VD, OS);
if (SynthesizedTarget) {
OS << SwiftLangSupport::SynthesizedUSRSeparator;
SwiftLangSupport::printUSR(SynthesizedTargetNTD, OS);
{
llvm::raw_svector_ostream OS(Info.OriginalUSR);
SwiftLangSupport::printUSR(VD, OS);
}
}
}
}
if (DefaultImplementationOf) {
llvm::raw_svector_ostream OS(Info.ProvideImplementationOfUSR);
SwiftLangSupport::printUSR((const ValueDecl*)DefaultImplementationOf, OS);
}
Info.IsUnavailable = AvailableAttr::isUnavailable(D);
Info.IsDeprecated = D->getAttrs().getDeprecated(D->getASTContext()) != nullptr;
Info.IsOptional = D->getAttrs().hasAttribute<OptionalAttr>();
if (!IsRef) {
llvm::raw_svector_ostream OS(Info.DocComment);
{
llvm::SmallString<128> DocBuffer;
{
llvm::raw_svector_ostream OSS(DocBuffer);
ide::getDocumentationCommentAsXML(D, OSS);
}
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;
}
initDocGenericParams(D, Info);
llvm::raw_svector_ostream LocalizationKeyOS(Info.LocalizationKey);
ide::getLocalizationKey(D, LocalizationKeyOS);
if (auto *VD = dyn_cast<ValueDecl>(D)) {
llvm::raw_svector_ostream OS(Info.FullyAnnotatedDecl);
if (SynthesizedTarget)
SwiftLangSupport::printFullyAnnotatedSynthesizedDeclaration(
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);
}
}
}
switch(D->getDeclContext()->getContextKind()) {
case DeclContextKind::AbstractClosureExpr:
case DeclContextKind::TopLevelCodeDecl:
case DeclContextKind::AbstractFunctionDecl:
case DeclContextKind::SubscriptDecl:
case DeclContextKind::EnumElementDecl:
case DeclContextKind::Initializer:
case DeclContextKind::SerializedLocal:
case DeclContextKind::ExtensionDecl:
case DeclContextKind::GenericTypeDecl:
break;
// We report sub-module information only for top-level decls.
case DeclContextKind::Module:
case DeclContextKind::FileUnit: {
if (auto *CD = D->getClangDecl()) {
if (auto *M = CD->getImportedOwningModule()) {
if (M->isSubModule()) {
llvm::raw_svector_ostream OS(Info.SubModuleName);
ModuleDecl::ReverseFullNameIterator(M).printForward(OS);
}
}
}
break;
}
}
return false;
}
static bool initDocEntityInfo(const TextEntity &Entity,
DocEntityInfo &Info) {
if (initDocEntityInfo(Entity.Dcl, Entity.SynthesizeTarget,
Entity.DefaultImplementationOf,
/*IsRef=*/false, Entity.IsSynthesizedExtension,
Info, Entity.Argument))
return true;
Info.Offset = Entity.Range.Offset;
Info.Length = Entity.Range.Length;
return false;
}
static const TypeDecl *getTypeDeclFromType(Type Ty) {
if (auto alias = dyn_cast<TypeAliasType>(Ty.getPointer()))
return alias->getDecl();
return Ty->getAnyNominal();
}
static void passInherits(const ValueDecl *D, DocInfoConsumer &Consumer) {
DocEntityInfo EntInfo;
if (initDocEntityInfo(D, {}, nullptr, /*IsRef=*/true, false, EntInfo))
return;
Consumer.handleInheritsEntity(EntInfo);
}
static void passConforms(const ValueDecl *D, DocInfoConsumer &Consumer) {
DocEntityInfo EntInfo;
if (initDocEntityInfo(D, {}, nullptr, /*IsRef=*/true, false, EntInfo))
return;
Consumer.handleConformsToEntity(EntInfo);
}
static void passInherits(ArrayRef<TypeLoc> InheritedTypes,
DocInfoConsumer &Consumer) {
for (auto Inherited : InheritedTypes) {
if (!Inherited.getType())
continue;
if (auto Proto = Inherited.getType()->getAs<ProtocolType>()) {
passConforms(Proto->getDecl(), Consumer);
continue;
}
if (auto ProtoComposition
= Inherited.getType()->getAs<ProtocolCompositionType>()) {
for (auto T : ProtoComposition->getMembers())
passInherits(TypeLoc::withoutLoc(T), Consumer);
continue;
}
if (auto TD = getTypeDeclFromType(Inherited.getType())) {
passInherits(TD, Consumer);
continue;
}
}
}
static void passConforms(ArrayRef<ValueDecl *> Dcls,
DocInfoConsumer &Consumer) {
for (auto D : Dcls)
passConforms(D, Consumer);
}
static void passExtends(const ValueDecl *D, DocInfoConsumer &Consumer) {
DocEntityInfo EntInfo;
if (initDocEntityInfo(D, {}, nullptr, /*IsRef=*/true, false, EntInfo))
return;
Consumer.handleExtendsEntity(EntInfo);
}
static void passInheritsAndConformancesForValueDecl(const ValueDecl *VD,
DocInfoConsumer &Consumer) {
if (auto Overridden = VD->getOverriddenDecl())
passInherits(Overridden, Consumer);
passConforms(VD->getSatisfiedProtocolRequirements(/*Sorted=*/true),
Consumer);
}
static void reportRelated(ASTContext &Ctx, const Decl *D,
TypeOrExtensionDecl SynthesizedTarget,
DocInfoConsumer &Consumer) {
if (!D || isa<ParamDecl>(D))
return;
if (const auto *ED = dyn_cast<ExtensionDecl>(D)) {
if (SynthesizedTarget) {
auto Extends = SynthesizedTarget.getBaseNominal();
passExtends(Extends, Consumer);
} else if (Type T = ED->getExtendedType()) {
if (auto TD = getTypeDeclFromType(T))
passExtends(TD, Consumer);
}
passInherits(ED->getInherited(), Consumer);
} else if (auto *TAD = dyn_cast<TypeAliasDecl>(D)) {
if (auto Ty = TAD->getDeclaredInterfaceType()) {
// If underlying type exists, report the inheritance and conformance of the
// underlying type.
if (auto NM = Ty->getAnyNominal()) {
passInherits(NM->getInherited(), Consumer);
passConforms(NM->getSatisfiedProtocolRequirements(/*Sorted=*/true),
Consumer);
return;
}
}
// Otherwise, report the inheritance of the type alias itself.
passInheritsAndConformancesForValueDecl(TAD, Consumer);
} else if (const auto *TD = dyn_cast<TypeDecl>(D)) {
llvm::SmallVector<TypeLoc, 4> AllInherits;
getInheritedForPrinting(TD, PrintOptions(), AllInherits);
passInherits(AllInherits, Consumer);
passConforms(TD->getSatisfiedProtocolRequirements(/*Sorted=*/true),
Consumer);
} else if (auto *VD = dyn_cast<ValueDecl>(D)) {
passInheritsAndConformancesForValueDecl(VD, Consumer);
}
}
static ArrayRef<const DeclAttribute*>
getDeclAttributes(const Decl *D, std::vector<const DeclAttribute*> &Scratch) {
for (auto Attr : D->getAttrs()) {
Scratch.push_back(Attr);
}
// For enum elements, inherit their parent enum decls' deprecated attributes.
if (auto *DE = dyn_cast<EnumElementDecl>(D)) {
for (auto Attr : DE->getParentEnum()->getAttrs()) {
if (auto Avail = dyn_cast<AvailableAttr>(Attr)) {
if (Avail->Deprecated || Avail->isUnconditionallyDeprecated()) {
Scratch.push_back(Attr);
}
}
}
}
return llvm::makeArrayRef(Scratch);
}
// Only reports @available.
// FIXME: Handle all attributes.
static void reportAttributes(ASTContext &Ctx,
const Decl *D,
DocInfoConsumer &Consumer) {
static UIdent AvailableAttrKind("source.lang.swift.attribute.availability");
static UIdent PlatformIOS("source.availability.platform.ios");
static UIdent PlatformOSX("source.availability.platform.osx");
static UIdent PlatformtvOS("source.availability.platform.tvos");
static UIdent PlatformWatchOS("source.availability.platform.watchos");
static UIdent PlatformIOSAppExt("source.availability.platform.ios_app_extension");
static UIdent PlatformOSXAppExt("source.availability.platform.osx_app_extension");
static UIdent PlatformtvOSAppExt("source.availability.platform.tvos_app_extension");
static UIdent PlatformWatchOSAppExt("source.availability.platform.watchos_app_extension");
std::vector<const DeclAttribute*> Scratch;
for (auto Attr : getDeclAttributes(D, Scratch)) {
if (auto Av = dyn_cast<AvailableAttr>(Attr)) {
UIdent PlatformUID;
switch (Av->Platform) {
case PlatformKind::none:
PlatformUID = UIdent(); break;
case PlatformKind::iOS:
PlatformUID = PlatformIOS; break;
case PlatformKind::OSX:
PlatformUID = PlatformOSX; break;
case PlatformKind::tvOS:
PlatformUID = PlatformtvOS; break;
case PlatformKind::watchOS:
PlatformUID = PlatformWatchOS; break;
case PlatformKind::iOSApplicationExtension:
PlatformUID = PlatformIOSAppExt; break;
case PlatformKind::OSXApplicationExtension:
PlatformUID = PlatformOSXAppExt; break;
case PlatformKind::tvOSApplicationExtension:
PlatformUID = PlatformtvOSAppExt; break;
case PlatformKind::watchOSApplicationExtension:
PlatformUID = PlatformWatchOSAppExt; break;
}
AvailableAttrInfo Info;
Info.AttrKind = AvailableAttrKind;
Info.IsUnavailable = Av->isUnconditionallyUnavailable();
Info.IsDeprecated = Av->isUnconditionallyDeprecated();
Info.Platform = PlatformUID;
Info.Message = Av->Message;
if (Av->Introduced)
Info.Introduced = *Av->Introduced;
if (Av->Deprecated)
Info.Deprecated = *Av->Deprecated;
if (Av->Obsoleted)
Info.Obsoleted = *Av->Obsoleted;
Consumer.handleAvailableAttribute(Info);
}
}
}
static void reportDocEntities(ASTContext &Ctx,
ArrayRef<TextEntity> Entities,
DocInfoConsumer &Consumer) {
for (auto &Entity : Entities) {
DocEntityInfo EntInfo;
if (initDocEntityInfo(Entity, EntInfo))
continue;
Consumer.startSourceEntity(EntInfo);
reportRelated(Ctx, Entity.Dcl,
Entity.IsSynthesizedExtension ? Entity.SynthesizeTarget
: TypeOrExtensionDecl(),
Consumer);
reportDocEntities(Ctx, Entity.SubEntities, Consumer);
reportAttributes(Ctx, Entity.Dcl, Consumer);
Consumer.finishSourceEntity(EntInfo.Kind);
}
}
namespace {
class DocSyntaxWalker : public SyntaxModelWalker {
SourceManager &SM;
unsigned BufferID;
ArrayRef<TextReference> References;
DocInfoConsumer &Consumer;
SourceLoc LastArgLoc;
SourceLoc LastParamLoc;
public:
DocSyntaxWalker(SourceManager &SM, unsigned BufferID,
ArrayRef<TextReference> References,
DocInfoConsumer &Consumer)
: SM(SM), BufferID(BufferID), References(References), Consumer(Consumer) {}
bool walkToNodePre(SyntaxNode Node) override {
unsigned Offset = SM.getLocOffsetInBuffer(Node.Range.getStart(), BufferID);
unsigned Length = Node.Range.getByteLength();
reportRefsUntil(Offset);
if (!References.empty() && References.front().Range.Offset == Offset)
return true;
switch (Node.Kind) {
case SyntaxNodeKind::EditorPlaceholder:
return true;
case SyntaxNodeKind::Keyword:
case SyntaxNodeKind::Identifier:
if (Node.Range.getStart() == LastArgLoc ||
Node.Range.getStart() == LastParamLoc)
return true;
break;
case SyntaxNodeKind::DollarIdent:
case SyntaxNodeKind::Integer:
case SyntaxNodeKind::Floating:
case SyntaxNodeKind::String:
case SyntaxNodeKind::StringInterpolationAnchor:
case SyntaxNodeKind::CommentLine:
case SyntaxNodeKind::CommentBlock:
case SyntaxNodeKind::CommentMarker:
case SyntaxNodeKind::CommentURL:
case SyntaxNodeKind::DocCommentLine:
case SyntaxNodeKind::DocCommentBlock:
case SyntaxNodeKind::DocCommentField:
case SyntaxNodeKind::TypeId:
case SyntaxNodeKind::BuildConfigKeyword:
case SyntaxNodeKind::BuildConfigId:
case SyntaxNodeKind::PoundDirectiveKeyword:
case SyntaxNodeKind::AttributeId:
case SyntaxNodeKind::AttributeBuiltin:
case SyntaxNodeKind::ObjectLiteral:
break;
}
DocEntityInfo Info;
Info.Kind = SwiftLangSupport::getUIDForSyntaxNodeKind(Node.Kind);
Info.Offset = Offset;
Info.Length = Length;
Consumer.handleAnnotation(Info);
return true;
}
void finished() {
reportRefsUntil(std::numeric_limits<unsigned>::max());
}
bool walkToSubStructurePre(SyntaxStructureNode Node) override {
if (Node.Kind == SyntaxStructureKind::Parameter) {
auto Param = dyn_cast<ParamDecl>(Node.Dcl);
auto passAnnotation = [&](UIdent Kind, SourceLoc Loc, Identifier Name) {
if (Loc.isInvalid())
return;
unsigned Offset = SM.getLocOffsetInBuffer(Loc, BufferID);
unsigned Length = Name.empty() ? 1 : Name.getLength();
reportRefsUntil(Offset);
DocEntityInfo Info;
Info.Kind = Kind;
Info.Offset = Offset;
Info.Length = Length;
Consumer.handleAnnotation(Info);
};
// Argument
static UIdent KindArgument("source.lang.swift.syntaxtype.argument");
passAnnotation(KindArgument, Param->getArgumentNameLoc(),
Param->getArgumentName());
LastArgLoc = Param->getArgumentNameLoc();
// Parameter
static UIdent KindParameter("source.lang.swift.syntaxtype.parameter");
passAnnotation(KindParameter, Param->getNameLoc(), Param->getName());
LastParamLoc = Param->getNameLoc();
}
return true;
}
private:
void reportRefsUntil(unsigned Offset) {
while (!References.empty() && References.front().Range.Offset < Offset) {
const TextReference &Ref = References.front();
References = References.slice(1);
DocEntityInfo Info;
if (initDocEntityInfo(Ref.Dcl, {}, nullptr, /*IsRef=*/true, false, Info))
continue;
Info.Offset = Ref.Range.Offset;
Info.Length = Ref.Range.Length;
Info.Ty = Ref.Ty;
Consumer.handleAnnotation(Info);
}
}
};
} // end anonymous namespace
static bool makeParserAST(CompilerInstance &CI, StringRef Text,
CompilerInvocation Invocation) {
Invocation.getFrontendOptions().InputsAndOutputs.clearInputs();
Invocation.setModuleName("main");
Invocation.setInputKind(InputFileKind::Swift);
std::unique_ptr<llvm::MemoryBuffer> Buf;
Buf = llvm::MemoryBuffer::getMemBuffer(Text, "<module-interface>");
Invocation.getFrontendOptions().InputsAndOutputs.addInput(
InputFile(Buf.get()->getBufferIdentifier(), false, Buf.get()));
if (CI.setup(Invocation))
return true;
CI.performParseOnly();
return false;
}
static void collectFuncEntities(std::vector<TextEntity> &Ents,
std::vector<TextEntity*> &FuncEntities) {
for (TextEntity &Ent : Ents) {
if (isa<AbstractFunctionDecl>(Ent.Dcl) || isa<SubscriptDecl>(Ent.Dcl)) {
// We are getting the entities via a pointer and later adding to their
// subentities; make sure it doesn't have subentities now or we are going
// to invalidate the pointers.
assert(Ent.SubEntities.empty());
FuncEntities.push_back(&Ent);
}
collectFuncEntities(Ent.SubEntities, FuncEntities);
}
}
static void addParameters(ArrayRef<Identifier> &ArgNames,
const ParameterList *paramList,
TextEntity &Ent,
SourceManager &SM,
unsigned BufferID) {
for (auto &param : *paramList) {
StringRef Arg;
if (!ArgNames.empty()) {
Identifier Id = ArgNames.front();
Arg = Id.empty() ? "_" : Id.str();
ArgNames = ArgNames.slice(1);
}
if (auto typeRepr = param->getTypeLoc().getTypeRepr()) {
SourceRange TypeRange = param->getTypeLoc().getSourceRange();
if (auto InOutTyR = dyn_cast_or_null<InOutTypeRepr>(typeRepr))
TypeRange = InOutTyR->getBase()->getSourceRange();
if (TypeRange.isInvalid())
continue;
unsigned StartOffs = SM.getLocOffsetInBuffer(TypeRange.Start, BufferID);
unsigned EndOffs =
SM.getLocOffsetInBuffer(Lexer::getLocForEndOfToken(SM, TypeRange.End),
BufferID);
TextRange TR{ StartOffs, EndOffs-StartOffs };
TextEntity Param(param, {}, nullptr, Arg, TR, StartOffs, false);
Ent.SubEntities.push_back(std::move(Param));
}
}
}
static void addParameters(const AbstractFunctionDecl *FD,
TextEntity &Ent,
SourceManager &SM,
unsigned BufferID) {
ArrayRef<Identifier> ArgNames;
DeclName Name = FD->getFullName();
if (Name) {
ArgNames = Name.getArgumentNames();
}
auto paramList = FD->getParameters();
addParameters(ArgNames, paramList, Ent, SM, BufferID);
}
static void addParameters(const SubscriptDecl *D,
TextEntity &Ent,
SourceManager &SM,
unsigned BufferID) {
ArrayRef<Identifier> ArgNames;
DeclName Name = D->getFullName();
if (Name) {
ArgNames = Name.getArgumentNames();
}
addParameters(ArgNames, D->getIndices(), Ent, SM, BufferID);
}
namespace {
class FuncWalker : public ASTWalker {
SourceManager &SM;
unsigned BufferID;
llvm::MutableArrayRef<TextEntity*> FuncEnts;
public:
FuncWalker(SourceManager &SM, unsigned BufferID,
llvm::MutableArrayRef<TextEntity*> FuncEnts)
: SM(SM), BufferID(BufferID), FuncEnts(FuncEnts) {}
bool walkToDeclPre(Decl *D) override {
if (D->isImplicit())
return false; // Skip body.
if (FuncEnts.empty())
return false;
if (!isa<AbstractFunctionDecl>(D) && !isa<SubscriptDecl>(D))
return true;
unsigned Offset = SM.getLocOffsetInBuffer(D->getLoc(), BufferID);
auto Found = FuncEnts.end();
if (FuncEnts.front()->LocOffset == Offset) {
Found = FuncEnts.begin();
} else {
Found = std::lower_bound(FuncEnts.begin(), FuncEnts.end(), Offset,
[](TextEntity *Ent, unsigned Offs) {
return Ent->LocOffset < Offs;
});
}
if (Found == FuncEnts.end() || (*Found)->LocOffset != Offset)
return false;
if (auto FD = dyn_cast<AbstractFunctionDecl>(D)) {
addParameters(FD, **Found, SM, BufferID);
} else {
addParameters(cast<SubscriptDecl>(D), **Found, SM, BufferID);
}
FuncEnts = llvm::MutableArrayRef<TextEntity*>(Found+1, FuncEnts.end());
return false; // skip body.
}
};
} // end anonymous namespace
static void addParameterEntities(CompilerInstance &CI,
SourceTextInfo &IFaceInfo) {
std::vector<TextEntity*> FuncEntities;
collectFuncEntities(IFaceInfo.TopEntities, FuncEntities);
llvm::MutableArrayRef<TextEntity*> FuncEnts(FuncEntities.data(),
FuncEntities.size());
for (auto Unit : CI.getMainModule()->getFiles()) {
auto SF = dyn_cast<SourceFile>(Unit);
if (!SF)
continue;
FuncWalker Walker(CI.getSourceMgr(), *SF->getBufferID(), FuncEnts);
SF->walk(Walker);
}
}
static void reportSourceAnnotations(const SourceTextInfo &IFaceInfo,
CompilerInstance &CI,
DocInfoConsumer &Consumer) {
for (auto Unit : CI.getMainModule()->getFiles()) {
auto SF = dyn_cast<SourceFile>(Unit);
if (!SF)
continue;
SyntaxModelContext SyntaxContext(*SF);
DocSyntaxWalker SyntaxWalker(CI.getSourceMgr(), *SF->getBufferID(),
IFaceInfo.References, Consumer);
SyntaxContext.walk(SyntaxWalker);
SyntaxWalker.finished();
}
}
static bool getModuleInterfaceInfo(ASTContext &Ctx, StringRef ModuleName,
SourceTextInfo &Info) {
// Load standard library so that Clang importer can use it.
auto *Stdlib = getModuleByFullName(Ctx, Ctx.StdlibModuleName);
if (!Stdlib)
return true;
auto *M = getModuleByFullName(Ctx, ModuleName);
if (!M)
return true;
PrintOptions Options = PrintOptions::printDocInterface();
ModuleTraversalOptions TraversalOptions = None;
TraversalOptions |= ModuleTraversal::VisitSubmodules;
TraversalOptions |= ModuleTraversal::VisitHidden;
SmallString<128> Text;
llvm::raw_svector_ostream OS(Text);
AnnotatingPrinter Printer(OS);
printModuleInterface(M, None, TraversalOptions, Printer, Options,
true);
Info.Text = OS.str();
Info.TopEntities = std::move(Printer.TopEntities);
Info.References = std::move(Printer.References);
return false;
}
static bool reportModuleDocInfo(CompilerInvocation Invocation,
StringRef ModuleName,
DocInfoConsumer &Consumer) {
CompilerInstance CI;
// Display diagnostics to stderr.
PrintingDiagnosticConsumer PrintDiags;
CI.addDiagnosticConsumer(&PrintDiags);
if (CI.setup(Invocation))
return true;
ASTContext &Ctx = CI.getASTContext();
registerIDERequestFunctions(Ctx.evaluator);
(void)createTypeChecker(Ctx);
SourceTextInfo IFaceInfo;
if (getModuleInterfaceInfo(Ctx, ModuleName, IFaceInfo))
return true;
CompilerInstance ParseCI;
if (makeParserAST(ParseCI, IFaceInfo.Text, Invocation))
return true;
addParameterEntities(ParseCI, IFaceInfo);
Consumer.handleSourceText(IFaceInfo.Text);
reportDocEntities(Ctx, IFaceInfo.TopEntities, Consumer);
reportSourceAnnotations(IFaceInfo, ParseCI, Consumer);
return false;
}
namespace {
class SourceDocASTWalker : public SourceEntityWalker {
public:
SourceManager &SM;
unsigned BufferID;
std::vector<TextEntity> TopEntities;
std::vector<TextEntity> EntitiesStack;
std::vector<TextReference> References;
SourceDocASTWalker(SourceManager &SM, unsigned BufferID)
: SM(SM), BufferID(BufferID) {}
~SourceDocASTWalker() override {
assert(EntitiesStack.empty());
}
bool walkToDeclPre(Decl *D, CharSourceRange Range) override {
if (!isa<ValueDecl>(D) && !isa<ExtensionDecl>(D))
return true;
if (isLocal(D))
return true;
TextRange TR = getTextRange(D->getSourceRange());
unsigned LocOffset = getOffset(Range.getStart());
EntitiesStack.emplace_back(D, TypeOrExtensionDecl(), nullptr, TR, LocOffset,
false);
return true;
}
bool walkToDeclPost(Decl *D) override {
if (EntitiesStack.empty() || EntitiesStack.back().Dcl != D)
return true;
TextEntity Entity = std::move(EntitiesStack.back());
EntitiesStack.pop_back();
if (EntitiesStack.empty())
TopEntities.push_back(Entity);
else
EntitiesStack.back().SubEntities.push_back(Entity);
return true;
}
bool visitDeclReference(ValueDecl *D, CharSourceRange Range,
TypeDecl *CtorTyRef, ExtensionDecl *ExtTyRef, Type Ty,
ReferenceMetaData Data) override {
if (Data.isImplicit)
return true;
unsigned StartOffset = getOffset(Range.getStart());
References.emplace_back(D, StartOffset, Range.getByteLength(), Ty);
return true;
}
bool visitSubscriptReference(ValueDecl *D, CharSourceRange Range,
ReferenceMetaData Data,
bool IsOpenBracket) override {
// Treat both open and close brackets equally
return visitDeclReference(D, Range, nullptr, nullptr, Type(), Data);
}
bool isLocal(Decl *D) const {
return isa<ParamDecl>(D) || D->getDeclContext()->getLocalContext();
}
unsigned getOffset(SourceLoc Loc) const {
return SM.getLocOffsetInBuffer(Loc, BufferID);
}
TextRange getTextRange(SourceRange R) const {
unsigned Start = getOffset(R.Start);
unsigned End = getOffset(R.End);
return TextRange{ Start, End-Start };
}
};
} // end anonymous namespace
static bool getSourceTextInfo(CompilerInstance &CI,
SourceTextInfo &Info) {
SourceManager &SM = CI.getSourceMgr();
unsigned BufID = CI.getInputBufferIDs().back();
SourceDocASTWalker Walker(SM, BufID);
Walker.walk(*CI.getMainModule());
CharSourceRange FullRange = SM.getRangeForBuffer(BufID);
Info.Text = SM.extractText(FullRange);
Info.TopEntities = std::move(Walker.TopEntities);
Info.References = std::move(Walker.References);
return false;
}
static bool reportSourceDocInfo(CompilerInvocation Invocation,
llvm::MemoryBuffer *InputBuf,
DocInfoConsumer &Consumer) {
CompilerInstance CI;
// Display diagnostics to stderr.
PrintingDiagnosticConsumer PrintDiags;
CI.addDiagnosticConsumer(&PrintDiags);
EditorDiagConsumer DiagConsumer;
CI.addDiagnosticConsumer(&DiagConsumer);
Invocation.getFrontendOptions().InputsAndOutputs.addInput(
InputFile(InputBuf->getBufferIdentifier(), false, InputBuf));
if (CI.setup(Invocation))
return true;
DiagConsumer.setInputBufferIDs(CI.getInputBufferIDs());
ASTContext &Ctx = CI.getASTContext();
CloseClangModuleFiles scopedCloseFiles(*Ctx.getClangModuleLoader());
CI.performSema();
// Setup a typechecker for protocol conformance resolving.
(void)createTypeChecker(Ctx);
SourceTextInfo SourceInfo;
if (getSourceTextInfo(CI, SourceInfo))
return true;
addParameterEntities(CI, SourceInfo);
reportDocEntities(Ctx, SourceInfo.TopEntities, Consumer);
reportSourceAnnotations(SourceInfo, CI, Consumer);
for (auto &Diag : DiagConsumer.getDiagnosticsForBuffer(
CI.getInputBufferIDs().back()))
Consumer.handleDiagnostic(Diag);
return false;
}
class RequestRefactoringEditConsumer::Implementation {
public:
CategorizedEditsReceiver Receiver;
std::vector<Edit> AllEdits;
std::vector<std::pair<unsigned, unsigned>> StartEnds;
std::vector<UIdent> UIds;
SmallString<64> ErrBuffer;
llvm::raw_svector_ostream OS;
PrintingDiagnosticConsumer DiagConsumer;
Implementation(CategorizedEditsReceiver Receiver):
Receiver(std::move(Receiver)), OS(ErrBuffer), DiagConsumer(OS) {}
~Implementation() {
if (DiagConsumer.didErrorOccur()) {
Receiver(RequestResult<ArrayRef<CategorizedEdits>>::fromError(OS.str()));
return;
}
assert(UIds.size() == StartEnds.size());
std::vector<CategorizedEdits> Results;
for (unsigned I = 0, N = UIds.size(); I < N; I ++) {
auto Pair = StartEnds[I];
Results.push_back({UIds[I],
llvm::makeArrayRef(AllEdits.data() + Pair.first,
Pair.second - Pair.first)});
}
Receiver(RequestResult<ArrayRef<CategorizedEdits>>::fromResult(Results));
}
void accept(SourceManager &SM, RegionType RegionType,
ArrayRef<Replacement> Replacements) {
unsigned Start = AllEdits.size();
std::transform(Replacements.begin(), Replacements.end(),
std::back_inserter(AllEdits),
[&](const Replacement &R) -> Edit {
std::pair<unsigned, unsigned>
Start = SM.getLineAndColumn(R.Range.getStart()),
End = SM.getLineAndColumn(R.Range.getEnd());
SmallVector<NoteRegion, 4> SubRanges;
auto RawRanges = R.RegionsWorthNote;
std::transform(RawRanges.begin(), RawRanges.end(),
std::back_inserter(SubRanges),
[](swift::ide::NoteRegion R) -> SourceKit::NoteRegion {
return {
SwiftLangSupport::getUIDForRefactoringRangeKind(R.Kind),
R.StartLine, R.StartColumn, R.EndLine, R.EndColumn,
R.ArgIndex
}; });
return {Start.first, Start.second, End.first, End.second, R.Text,
std::move(SubRanges)};
});
unsigned End = AllEdits.size();
StartEnds.emplace_back(Start, End);
UIds.push_back(SwiftLangSupport::getUIDForRegionType(RegionType));
}
};
RequestRefactoringEditConsumer::
RequestRefactoringEditConsumer(CategorizedEditsReceiver Receiver) :
Impl(*new Implementation(Receiver)) {}
RequestRefactoringEditConsumer::
~RequestRefactoringEditConsumer() { delete &Impl; };
void RequestRefactoringEditConsumer::
accept(SourceManager &SM, RegionType RegionType,
ArrayRef<Replacement> Replacements) {
Impl.accept(SM, RegionType, Replacements);
}
void RequestRefactoringEditConsumer::handleDiagnostic(
SourceManager &SM, SourceLoc Loc, DiagnosticKind Kind,
StringRef FormatString, ArrayRef<DiagnosticArgument> FormatArgs,
const DiagnosticInfo &Info,
const SourceLoc bufferIndirectlyCausingDiagnostic) {
Impl.DiagConsumer.handleDiagnostic(SM, Loc, Kind, FormatString, FormatArgs,
Info, bufferIndirectlyCausingDiagnostic);
}
class RequestRenameRangeConsumer::Implementation {
CategorizedRenameRangesReceiver Receiver;
std::string ErrBuffer;
llvm::raw_string_ostream OS;
std::vector<CategorizedRenameRanges> CategorizedRanges;
public:
PrintingDiagnosticConsumer DiagConsumer;
public:
Implementation(CategorizedRenameRangesReceiver Receiver)
: Receiver(Receiver), OS(ErrBuffer), DiagConsumer(OS) {}
~Implementation() {
if (DiagConsumer.didErrorOccur()) {
Receiver(RequestResult<ArrayRef<CategorizedRenameRanges>>::fromError(OS.str()));
return;
}
Receiver(RequestResult<ArrayRef<CategorizedRenameRanges>>::fromResult(CategorizedRanges));
}
void accept(SourceManager &SM, RegionType RegionType,
ArrayRef<ide::RenameRangeDetail> Ranges) {
CategorizedRenameRanges Results;
Results.Category = SwiftLangSupport::getUIDForRegionType(RegionType);
for (const auto &R : Ranges) {
SourceKit::RenameRangeDetail Result;
std::tie(Result.StartLine, Result.StartColumn) =
SM.getLineAndColumn(R.Range.getStart());
std::tie(Result.EndLine, Result.EndColumn) =
SM.getLineAndColumn(R.Range.getEnd());
Result.ArgIndex = R.Index;
Result.Kind =
SwiftLangSupport::getUIDForRefactoringRangeKind(R.RangeKind);
Results.Ranges.push_back(std::move(Result));
}
CategorizedRanges.push_back(std::move(Results));
}
};
RequestRenameRangeConsumer::RequestRenameRangeConsumer(
CategorizedRenameRangesReceiver Receiver)
: Impl(*new Implementation(Receiver)) {}
RequestRenameRangeConsumer::~RequestRenameRangeConsumer() { delete &Impl; }
void RequestRenameRangeConsumer::accept(
SourceManager &SM, RegionType RegionType,
ArrayRef<ide::RenameRangeDetail> Ranges) {
Impl.accept(SM, RegionType, Ranges);
}
void RequestRenameRangeConsumer::handleDiagnostic(
SourceManager &SM, SourceLoc Loc, DiagnosticKind Kind,
StringRef FormatString, ArrayRef<DiagnosticArgument> FormatArgs,
const DiagnosticInfo &Info,
const SourceLoc bufferIndirectlyCausingDiagnostic) {
Impl.DiagConsumer.handleDiagnostic(SM, Loc, Kind, FormatString, FormatArgs,
Info, bufferIndirectlyCausingDiagnostic);
}
static NameUsage getNameUsage(RenameType Type) {
switch (Type) {
case RenameType::Definition:
return NameUsage::Definition;
case RenameType::Reference:
return NameUsage::Reference;
case RenameType::Call:
return NameUsage::Call;
case RenameType::Unknown:
return NameUsage::Unknown;
}
}
static std::vector<RenameLoc>
getSyntacticRenameLocs(ArrayRef<RenameLocations> RenameLocations);
void SwiftLangSupport::
syntacticRename(llvm::MemoryBuffer *InputBuf,
ArrayRef<RenameLocations> RenameLocations,
ArrayRef<const char*> Args,
CategorizedEditsReceiver Receiver) {
std::string Error;
CompilerInstance ParseCI;
PrintingDiagnosticConsumer PrintDiags;
ParseCI.addDiagnosticConsumer(&PrintDiags);
SourceFile *SF = getSyntacticSourceFile(InputBuf, Args, ParseCI, Error);
if (!SF) {
Receiver(RequestResult<ArrayRef<CategorizedEdits>>::fromError(Error));
return;
}
auto RenameLocs = getSyntacticRenameLocs(RenameLocations);
RequestRefactoringEditConsumer EditConsumer(Receiver);
swift::ide::syntacticRename(SF, RenameLocs, EditConsumer, EditConsumer);
}
void SwiftLangSupport::findRenameRanges(
llvm::MemoryBuffer *InputBuf, ArrayRef<RenameLocations> RenameLocations,
ArrayRef<const char *> Args, CategorizedRenameRangesReceiver Receiver) {
std::string Error;
CompilerInstance ParseCI;
PrintingDiagnosticConsumer PrintDiags;
ParseCI.addDiagnosticConsumer(&PrintDiags);
SourceFile *SF = getSyntacticSourceFile(InputBuf, Args, ParseCI, Error);
if (!SF) {
Receiver(RequestResult<ArrayRef<CategorizedRenameRanges>>::fromError(Error));
return;
}
auto RenameLocs = getSyntacticRenameLocs(RenameLocations);
RequestRenameRangeConsumer Consumer(Receiver);
swift::ide::findSyntacticRenameRanges(SF, RenameLocs, Consumer, Consumer);
}
void SwiftLangSupport::findLocalRenameRanges(
StringRef Filename, unsigned Line, unsigned Column, unsigned Length,
ArrayRef<const char *> Args, CategorizedRenameRangesReceiver Receiver) {
std::string Error;
SwiftInvocationRef Invok = ASTMgr->getInvocation(Args, Filename, Error);
if (!Invok) {
LOG_WARN_FUNC("failed to create an ASTInvocation: " << Error);
Receiver(RequestResult<ArrayRef<CategorizedRenameRanges>>::fromError(Error));
return;
}
struct LocalRenameRangeASTConsumer : public SwiftASTConsumer {
unsigned Line, Column, Length;
CategorizedRenameRangesReceiver Receiver;
LocalRenameRangeASTConsumer(unsigned Line, unsigned Column, unsigned Length,
CategorizedRenameRangesReceiver Receiver)
: Line(Line), Column(Column), Length(Length),
Receiver(std::move(Receiver)) {}
void handlePrimaryAST(ASTUnitRef AstUnit) override {
auto &SF = AstUnit->getPrimarySourceFile();
swift::ide::RangeConfig Range{*SF.getBufferID(), Line, Column, Length};
RequestRenameRangeConsumer Consumer(std::move(Receiver));
swift::ide::findLocalRenameRanges(&SF, Range, Consumer, Consumer);
}
void cancelled() override {
Receiver(RequestResult<ArrayRef<CategorizedRenameRanges>>::cancelled());
}
void failed(StringRef Error) override {
Receiver(RequestResult<ArrayRef<CategorizedRenameRanges>>::fromError(Error));
}
};
auto ASTConsumer = std::make_shared<LocalRenameRangeASTConsumer>(
Line, Column, Length, std::move(Receiver));
/// FIXME: When request cancellation is implemented and Xcode adopts it,
/// don't use 'OncePerASTToken'.
static const char OncePerASTToken = 0;
getASTManager()->processASTAsync(Invok, ASTConsumer, &OncePerASTToken,
llvm::vfs::getRealFileSystem());
}
SourceFile *SwiftLangSupport::getSyntacticSourceFile(
llvm::MemoryBuffer *InputBuf, ArrayRef<const char *> Args,
CompilerInstance &ParseCI, std::string &Error) {
CompilerInvocation Invocation;
bool Failed = getASTManager()->initCompilerInvocationNoInputs(
Invocation, Args, ParseCI.getDiags(), Error);
if (Failed) {
Error = "Compiler invocation init failed";
return nullptr;
}
Invocation.setInputKind(InputFileKind::Swift);
Invocation.getFrontendOptions().InputsAndOutputs.addInput(
InputFile(InputBuf->getBufferIdentifier(), false, InputBuf));
if (ParseCI.setup(Invocation)) {
Error = "Compiler invocation set up failed";
return nullptr;
}
ParseCI.performParseOnly(/*EvaluateConditionals*/true);
SourceFile *SF = nullptr;
unsigned BufferID = ParseCI.getInputBufferIDs().back();
for (auto Unit : ParseCI.getMainModule()->getFiles()) {
if (auto Current = dyn_cast<SourceFile>(Unit)) {
if (Current->getBufferID().getValue() == BufferID) {
SF = Current;
break;
}
}
}
if (!SF)
Error = "Failed to determine SourceFile for input buffer";
return SF;
}
static std::vector<RenameLoc>
getSyntacticRenameLocs(ArrayRef<RenameLocations> RenameLocations) {
std::vector<RenameLoc> RenameLocs;
for(const auto &Locations: RenameLocations) {
for(const auto &Location: Locations.LineColumnLocs) {
RenameLocs.push_back({Location.Line, Location.Column,
getNameUsage(Location.Type), Locations.OldName, Locations.NewName,
Locations.IsFunctionLike, Locations.IsNonProtocolType});
}
}
return RenameLocs;
}
void SwiftLangSupport::getDocInfo(llvm::MemoryBuffer *InputBuf,
StringRef ModuleName,
ArrayRef<const char *> Args,
DocInfoConsumer &Consumer) {
CompilerInstance CI;
// Display diagnostics to stderr.
PrintingDiagnosticConsumer PrintDiags;
CI.addDiagnosticConsumer(&PrintDiags);
CompilerInvocation Invocation;
std::string Error;
bool Failed = getASTManager()->initCompilerInvocationNoInputs(
Invocation, Args, CI.getDiags(), Error, /*AllowInputs=*/false);
if (Failed) {
Consumer.failed(Error);
return;
}
Invocation.getClangImporterOptions().ImportForwardDeclarations = true;
if (!ModuleName.empty()) {
bool Error = reportModuleDocInfo(Invocation, ModuleName, Consumer);
if (Error)
Consumer.failed("Error occurred");
return;
}
Failed = reportSourceDocInfo(Invocation, InputBuf, Consumer);
if (Failed)
Consumer.failed("Error occurred");
}
void SwiftLangSupport::
findModuleGroups(StringRef ModuleName, ArrayRef<const char *> Args,
std::function<void(const RequestResult<ArrayRef<StringRef>> &)> Receiver) {
CompilerInvocation Invocation;
Invocation.getClangImporterOptions().ImportForwardDeclarations = true;
Invocation.getFrontendOptions().InputsAndOutputs.clearInputs();
CompilerInstance CI;
// Display diagnostics to stderr.
PrintingDiagnosticConsumer PrintDiags;
CI.addDiagnosticConsumer(&PrintDiags);
std::vector<StringRef> Groups;
std::string Error;
if (getASTManager()->initCompilerInvocationNoInputs(Invocation, Args,
CI.getDiags(), Error)) {
Receiver(RequestResult<ArrayRef<StringRef>>::fromError(Error));
return;
}
if (CI.setup(Invocation)) {
Error = "Compiler invocation set up fails.";
Receiver(RequestResult<ArrayRef<StringRef>>::fromError(Error));
return;
}
ASTContext &Ctx = CI.getASTContext();
// Setup a typechecker for protocol conformance resolving.
(void)createTypeChecker(Ctx);
// Load standard library so that Clang importer can use it.
auto *Stdlib = getModuleByFullName(Ctx, Ctx.StdlibModuleName);
if (!Stdlib) {
Error = "Cannot load stdlib.";
Receiver(RequestResult<ArrayRef<StringRef>>::fromError(Error));
return;
}
auto *M = getModuleByFullName(Ctx, ModuleName);
if (!M) {
Error = "Cannot find the module.";
Receiver(RequestResult<ArrayRef<StringRef>>::fromError(Error));
return;
}
std::vector<StringRef> Scratch;
Receiver(RequestResult<ArrayRef<StringRef>>::fromResult(
collectModuleGroups(M, Scratch)));
}