blob: 0ec93dbe98583a1b4f240c2b8c5c305dcf4ddc29 [file] [log] [blame]
//===--- 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)));
}