| //===--- TypeReconstruction.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 "swift/IDE/Utils.h" |
| #include "swift/AST/ASTContext.h" |
| #include "swift/AST/Decl.h" |
| #include "swift/AST/GenericSignature.h" |
| #include "swift/AST/NameLookup.h" |
| #include "swift/AST/Types.h" |
| #include "swift/AST/SubstitutionMap.h" |
| #include "swift/Demangling/Demangle.h" |
| #include "swift/Demangling/ManglingMacros.h" |
| #include "swift/ClangImporter/ClangImporter.h" |
| #include "swift/Strings.h" |
| |
| #include <cstdio> |
| #include <cstdarg> |
| #include <mutex> // std::once |
| |
| using namespace swift; |
| |
| // FIXME: replace with std::string and StringRef as appropriate to each case. |
| using ConstString = const std::string; |
| |
| static std::string stringWithFormat(const char *fmt_str, ...) { |
| int final_n, n = ((int)strlen(fmt_str)) * 2; |
| std::string str; |
| std::unique_ptr<char[]> formatted; |
| va_list ap; |
| while (1) { |
| formatted.reset(new char[n]); |
| strcpy(&formatted[0], fmt_str); |
| va_start(ap, fmt_str); |
| final_n = vsnprintf(&formatted[0], n, fmt_str, ap); |
| va_end(ap); |
| if (final_n < 0 || final_n >= n) |
| n += abs(final_n - n + 1); |
| else |
| break; |
| } |
| return std::string(formatted.get()); |
| } |
| |
| static bool |
| CompareFunctionTypes(const AnyFunctionType *f, const AnyFunctionType *g, |
| Optional<std::vector<StringRef>> fLabels = None, |
| Optional<std::vector<StringRef>> gLabels = None, |
| bool *input_matches = nullptr, |
| bool *output_matches = nullptr); |
| |
| static Optional<ClangTypeKind> |
| GetClangTypeKindFromSwiftKind(DeclKind decl_kind) { |
| Optional<ClangTypeKind> clangTypeKind; |
| switch (decl_kind) { |
| case DeclKind::Class: |
| return ClangTypeKind::ObjCClass; |
| case DeclKind::Protocol: |
| return ClangTypeKind::ObjCProtocol; |
| case DeclKind::TypeAlias: |
| return ClangTypeKind::Typedef; |
| case DeclKind::Struct: |
| return ClangTypeKind::Tag; |
| default: |
| return None; |
| } |
| } |
| |
| class DeclsLookupSource { |
| public: |
| using ValueDecls = SmallVectorImpl<ValueDecl *>; |
| |
| private: |
| class VisibleDeclsConsumer : public VisibleDeclConsumer { |
| private: |
| std::vector<ValueDecl *> m_decls; |
| |
| public: |
| void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override { |
| m_decls.push_back(VD); |
| } |
| ~VisibleDeclsConsumer() override = default; |
| explicit operator bool() { return !m_decls.empty(); } |
| |
| decltype(m_decls)::const_iterator begin() { return m_decls.begin(); } |
| |
| decltype(m_decls)::const_iterator end() { return m_decls.end(); } |
| }; |
| |
| bool lookupQualified(ModuleDecl *entry, DeclBaseName name, NLOptions options, |
| LazyResolver *typeResolver, ValueDecls &decls) { |
| if (!entry) |
| return false; |
| size_t decls_size = decls.size(); |
| entry->lookupQualified(ModuleType::get(entry), name, options, typeResolver, |
| decls); |
| return decls.size() > decls_size; |
| } |
| |
| bool lookupValue(ModuleDecl *entry, DeclBaseName name, |
| ModuleDecl::AccessPathTy accessPath, NLKind lookupKind, |
| ValueDecls &decls) { |
| if (!entry) |
| return false; |
| size_t decls_size = decls.size(); |
| entry->lookupValue(accessPath, name, lookupKind, decls); |
| return decls.size() > decls_size; |
| } |
| |
| public: |
| enum class LookupKind { |
| SwiftModule, |
| ClangImporter, |
| Decl, |
| Extension, |
| Invalid |
| }; |
| |
| using PrivateDeclIdentifier = Optional<std::string>; |
| |
| static DeclsLookupSource |
| GetDeclsLookupSource(ASTContext &ast, ConstString module_name, |
| bool allow_clang_importer = true) { |
| assert(!module_name.empty()); |
| static ConstString g_ObjectiveCModule(MANGLING_MODULE_OBJC); |
| static ConstString g_BuiltinModule(BUILTIN_NAME); |
| static ConstString g_CModule(MANGLING_MODULE_CLANG_IMPORTER); |
| if (allow_clang_importer) { |
| if (module_name == g_ObjectiveCModule || module_name == g_CModule) |
| return DeclsLookupSource(&ast, module_name); |
| } |
| |
| ModuleDecl *module = module_name == g_BuiltinModule |
| ? ast.TheBuiltinModule |
| : ast.getModuleByName(module_name); |
| if (module == nullptr) |
| return DeclsLookupSource(); |
| return DeclsLookupSource(module); |
| } |
| |
| static DeclsLookupSource GetDeclsLookupSource(NominalTypeDecl *decl) { |
| assert(decl); |
| return DeclsLookupSource(decl); |
| } |
| |
| static DeclsLookupSource GetDeclsLookupSource(DeclsLookupSource source, |
| NominalTypeDecl *decl) { |
| assert(source._type == LookupKind::SwiftModule); |
| assert(source._module); |
| assert(decl); |
| return DeclsLookupSource(source._module, decl); |
| } |
| |
| void lookupByMangledName(DeclBaseName name, DeclKind decl_kind, |
| ValueDecls &result) { |
| if (_type == LookupKind::ClangImporter) { |
| ASTContext *ast_ctx = _clang_crawler._ast; |
| if (ast_ctx) { |
| ClangImporter *swift_clang_importer = |
| (ClangImporter *)ast_ctx->getClangModuleLoader(); |
| if (!swift_clang_importer) |
| return; |
| |
| Optional<ClangTypeKind> clangTypeKind = |
| GetClangTypeKindFromSwiftKind(decl_kind); |
| if (clangTypeKind) { |
| swift_clang_importer->lookupTypeDecl(name.getIdentifier().str(), |
| clangTypeKind.getValue(), |
| [&](TypeDecl *type_decl) { |
| result.push_back(type_decl); |
| }); |
| return; |
| } else { |
| VisibleDeclsConsumer consumer; |
| swift_clang_importer->lookupValue(name, consumer); |
| auto iter = consumer.begin(), end = consumer.end(); |
| while (iter != end) { |
| result.push_back(*iter); |
| iter++; |
| } |
| return; |
| } |
| } |
| } else if (_type == LookupKind::SwiftModule) { |
| lookupQualified(_module, name, NLOptions(), /*typeResolver*/nullptr, |
| result); |
| } |
| return; |
| } |
| |
| void lookupRelatedEntity(StringRef name, StringRef related_entity_kind, |
| DeclKind decl_kind, ValueDecls &result) { |
| switch (_type) { |
| case LookupKind::ClangImporter: { |
| ASTContext *ast_ctx = _clang_crawler._ast; |
| if (!ast_ctx) |
| return; |
| ClangImporter *swift_clang_importer = |
| (ClangImporter *)ast_ctx->getClangModuleLoader(); |
| if (!swift_clang_importer) |
| return; |
| Optional<ClangTypeKind> clang_kind = |
| GetClangTypeKindFromSwiftKind(decl_kind); |
| if (!clang_kind) |
| return; |
| swift_clang_importer->lookupRelatedEntity(name, clang_kind.getValue(), |
| related_entity_kind, |
| [&](TypeDecl *found) { |
| result.push_back(found); |
| }); |
| return; |
| } |
| case LookupKind::SwiftModule: |
| case LookupKind::Decl: |
| case LookupKind::Extension: |
| return; |
| case LookupKind::Invalid: |
| return; |
| } |
| } |
| |
| void lookupValue(ModuleDecl::AccessPathTy path, DeclBaseName name, NLKind kind, |
| ValueDecls &result) { |
| if (_type == LookupKind::ClangImporter) { |
| ASTContext *ast_ctx = _clang_crawler._ast; |
| if (ast_ctx) { |
| VisibleDeclsConsumer consumer; |
| ClangImporter *swift_clang_importer = |
| (ClangImporter *)ast_ctx->getClangModuleLoader(); |
| if (!swift_clang_importer) |
| return; |
| swift_clang_importer->lookupValue(name, consumer); |
| if (consumer) { |
| auto iter = consumer.begin(), end = consumer.end(); |
| while (iter != end) { |
| result.push_back(*iter); |
| iter++; |
| } |
| return; |
| } |
| } |
| } else if (_type == LookupKind::SwiftModule) |
| _module->lookupValue(path, name, kind, result); |
| else if (_type == LookupKind::Extension) { |
| auto results = _extension._decl->lookupDirect(DeclName(name)); |
| result.append(results.begin(), results.end()); |
| } |
| return; |
| } |
| |
| void lookupMember(DeclName id, Identifier priv_decl_id, ValueDecls &result) { |
| if (_type == LookupKind::Decl) |
| return lookupMember(_decl, id, priv_decl_id, result); |
| if (_type == LookupKind::SwiftModule) |
| return lookupMember(_module, id, priv_decl_id, result); |
| if (_type == LookupKind::Extension) |
| return lookupMember(_extension._decl, id, priv_decl_id, result); |
| return; |
| } |
| |
| void lookupMember(DeclContext *decl_ctx, DeclName id, Identifier priv_decl_id, |
| ValueDecls &result) { |
| if (_type == LookupKind::Decl) |
| _decl->getModuleContext()->lookupMember(result, decl_ctx, id, |
| priv_decl_id); |
| else if (_type == LookupKind::SwiftModule) |
| _module->lookupMember(result, decl_ctx, id, priv_decl_id); |
| else if (_type == LookupKind::Extension) |
| _extension._module->lookupMember(result, decl_ctx, id, priv_decl_id); |
| return; |
| } |
| |
| TypeDecl *lookupLocalType(StringRef key) { |
| switch (_type) { |
| case LookupKind::SwiftModule: |
| return _module->lookupLocalType(key); |
| case LookupKind::Decl: |
| return _decl->getModuleContext()->lookupLocalType(key); |
| case LookupKind::Extension: |
| return _extension._module->lookupLocalType(key); |
| case LookupKind::Invalid: |
| return nullptr; |
| case LookupKind::ClangImporter: |
| return nullptr; |
| } |
| |
| llvm_unreachable("Unhandled LookupKind in switch."); |
| } |
| |
| ConstString GetName() const { |
| switch (_type) { |
| case LookupKind::Invalid: |
| return ConstString("Invalid"); |
| case LookupKind::ClangImporter: |
| return ConstString("ClangImporter"); |
| case LookupKind::SwiftModule: |
| return ConstString(_module->getName().get()); |
| case LookupKind::Decl: |
| return ConstString(_decl->getName().get()); |
| case LookupKind::Extension: |
| SmallString<64> builder; |
| builder.append("ext "); |
| builder.append(_extension._decl->getNameStr()); |
| builder.append(" in "); |
| builder.append(_module->getNameStr()); |
| return builder.str(); |
| } |
| |
| llvm_unreachable("Unhandled LookupKind in switch."); |
| } |
| |
| ~DeclsLookupSource() {} |
| |
| DeclsLookupSource(const DeclsLookupSource &rhs) : _type(rhs._type) { |
| switch (_type) { |
| case LookupKind::Invalid: |
| break; |
| case LookupKind::ClangImporter: |
| _clang_crawler._ast = rhs._clang_crawler._ast; |
| break; |
| case LookupKind::SwiftModule: |
| _module = rhs._module; |
| break; |
| case LookupKind::Decl: |
| _decl = rhs._decl; |
| _extension._decl = rhs._extension._decl; |
| _extension._module = rhs._extension._module; |
| break; |
| case LookupKind::Extension: |
| _extension._decl = rhs._extension._decl; |
| _extension._module = rhs._extension._module; |
| break; |
| } |
| } |
| |
| DeclsLookupSource &operator=(const DeclsLookupSource &rhs) { |
| if (this != &rhs) { |
| _type = rhs._type; |
| switch (_type) { |
| case LookupKind::Invalid: |
| break; |
| case LookupKind::ClangImporter: |
| _clang_crawler._ast = rhs._clang_crawler._ast; |
| break; |
| case LookupKind::SwiftModule: |
| _module = rhs._module; |
| break; |
| case LookupKind::Decl: |
| _decl = rhs._decl; |
| _extension._decl = rhs._extension._decl; |
| _extension._module = rhs._extension._module; |
| break; |
| case LookupKind::Extension: |
| _extension._decl = rhs._extension._decl; |
| _extension._module = rhs._extension._module; |
| break; |
| } |
| } |
| return *this; |
| } |
| |
| void Clear() { |
| // no need to explicitly clean either pointer |
| _type = LookupKind::Invalid; |
| } |
| |
| DeclsLookupSource() : _type(LookupKind::Invalid), _module(nullptr) {} |
| |
| operator bool() { |
| switch (_type) { |
| case LookupKind::Invalid: |
| return false; |
| case LookupKind::ClangImporter: |
| return _clang_crawler._ast != nullptr; |
| case LookupKind::SwiftModule: |
| return _module != nullptr; |
| case LookupKind::Decl: |
| return _decl != nullptr; |
| case LookupKind::Extension: |
| return (_extension._decl != nullptr) && (_extension._module != nullptr); |
| } |
| |
| llvm_unreachable("Unhandled LookupKind in switch."); |
| } |
| |
| bool IsExtension() { |
| return (this->operator bool()) && (_type == LookupKind::Extension); |
| } |
| |
| NominalTypeDecl *GetExtendedDecl() { |
| assert(IsExtension()); |
| return _extension._decl; |
| } |
| |
| private: |
| LookupKind _type; |
| |
| union { |
| ModuleDecl *_module; |
| struct { |
| ASTContext *_ast; |
| } _clang_crawler; |
| NominalTypeDecl *_decl; |
| struct { |
| ModuleDecl *_module; // extension in this module |
| NominalTypeDecl *_decl; // for this type |
| } _extension; |
| }; |
| |
| DeclsLookupSource(ModuleDecl *_m) { |
| if (_m) { |
| _module = _m; |
| _type = LookupKind::SwiftModule; |
| } else |
| _type = LookupKind::Invalid; |
| } |
| |
| DeclsLookupSource(ASTContext *_a, ConstString _m) { |
| // it is fine for the ASTContext to be null, so don't actually even |
| // lldbassert there |
| if (_a) { |
| _clang_crawler._ast = _a; |
| _type = LookupKind::ClangImporter; |
| } else |
| _type = LookupKind::Invalid; |
| } |
| |
| DeclsLookupSource(NominalTypeDecl *_d) { |
| if (_d) { |
| _decl = _d; |
| _type = LookupKind::Decl; |
| } else |
| _type = LookupKind::Invalid; |
| } |
| |
| DeclsLookupSource(ModuleDecl *_m, NominalTypeDecl *_d) { |
| if (_m && _d) { |
| _extension._decl = _d; |
| _extension._module = _m; |
| _type = LookupKind::Extension; |
| } else |
| _type = LookupKind::Invalid; |
| } |
| }; |
| |
| struct VisitNodeResult { |
| DeclsLookupSource _module; |
| std::vector<Decl *> _decls; |
| std::vector<Type> _types; |
| TupleTypeElt _tuple_type_element; |
| std::string _error; |
| VisitNodeResult() |
| : _module(), _decls(), _types(), _tuple_type_element(), _error() {} |
| |
| bool HasSingleType() { return _types.size() == 1 && _types.front(); } |
| |
| void Clear() { |
| _module.Clear(); |
| _decls.clear(); |
| _types.clear(); |
| _tuple_type_element = TupleTypeElt(); |
| _error.clear(); |
| } |
| }; |
| |
| static Identifier |
| GetIdentifier(ASTContext *ast, |
| const DeclsLookupSource::PrivateDeclIdentifier &priv_decl_id) { |
| do { |
| if (!ast) |
| break; |
| if (!priv_decl_id.hasValue()) |
| break; |
| return ast->getIdentifier(priv_decl_id.getValue().c_str()); |
| } while (false); |
| return Identifier(); |
| } |
| |
| static bool FilterDeclsForKind(DeclKind decl_kind, |
| ArrayRef<swift::ValueDecl *> decls, |
| VisitNodeResult &result) { |
| for (auto decl : decls) { |
| // Note: Clang nodes are filtered ahead of time based on their Clang decl |
| // kind. |
| if (decl->getKind() != decl_kind && !decl->hasClangNode()) |
| continue; |
| |
| result._decls = {decl}; |
| Type decl_type; |
| if (decl->hasInterfaceType()) { |
| decl_type = decl->getInterfaceType(); |
| MetatypeType *meta_type = decl_type->getAs<MetatypeType>(); |
| if (meta_type) |
| decl_type = meta_type->getInstanceType(); |
| } |
| result._types = {decl_type}; |
| return true; |
| } |
| |
| return false; |
| } |
| |
| static bool FindFirstNamedDeclWithKind( |
| ASTContext *ast, const DeclBaseName &name, DeclKind decl_kind, |
| VisitNodeResult &result, |
| DeclsLookupSource::PrivateDeclIdentifier priv_decl_id = |
| DeclsLookupSource::PrivateDeclIdentifier()) |
| |
| { |
| if (!result._decls.empty()) { |
| Decl *parent_decl = result._decls.back(); |
| if (parent_decl) { |
| auto nominal_decl = dyn_cast<NominalTypeDecl>(parent_decl); |
| |
| if (nominal_decl) { |
| DeclsLookupSource lookup( |
| DeclsLookupSource::GetDeclsLookupSource(nominal_decl)); |
| SmallVector<ValueDecl *, 4> decls; |
| lookup.lookupMember(name, GetIdentifier(ast, priv_decl_id), decls); |
| |
| if (FilterDeclsForKind(decl_kind, decls, result)) |
| return true; |
| } |
| } |
| } else if (result._module) { |
| SmallVector<ValueDecl *, 4> decls; |
| if (priv_decl_id) |
| result._module.lookupMember(name, GetIdentifier(ast, priv_decl_id), |
| decls); |
| else |
| result._module.lookupByMangledName(name, decl_kind, decls); |
| if (FilterDeclsForKind(decl_kind, decls, result)) |
| return true; |
| } |
| result.Clear(); |
| result._error = "Generic Error"; |
| return false; |
| } |
| |
| static size_t |
| FindNamedDecls(ASTContext *ast, const DeclBaseName &name, VisitNodeResult &result, |
| DeclsLookupSource::PrivateDeclIdentifier priv_decl_id = |
| DeclsLookupSource::PrivateDeclIdentifier()) { |
| if (!result._decls.empty()) { |
| Decl *parent_decl = result._decls.back(); |
| result._decls.clear(); |
| result._types.clear(); |
| if (parent_decl) { |
| |
| if (auto nominal_decl = dyn_cast<NominalTypeDecl>(parent_decl)) { |
| DeclsLookupSource lookup( |
| DeclsLookupSource::GetDeclsLookupSource(nominal_decl)); |
| SmallVector<ValueDecl *, 4> decls; |
| lookup.lookupMember(name, GetIdentifier(ast, priv_decl_id), decls); |
| if (decls.empty()) { |
| result._error = stringWithFormat( |
| "no decl found in '%s' (DeclKind=%u)", |
| name.userFacingName().str().c_str(), |
| nominal_decl->getName().get(), (uint32_t)nominal_decl->getKind()); |
| } else { |
| for (ValueDecl *decl : decls) { |
| if (decl->hasInterfaceType()) { |
| result._decls.push_back(decl); |
| Type decl_type; |
| if (decl->hasInterfaceType()) { |
| decl_type = decl->getInterfaceType(); |
| MetatypeType *meta_type = decl_type->getAs<MetatypeType>(); |
| if (meta_type) |
| decl_type = meta_type->getInstanceType(); |
| } |
| result._types.push_back(decl_type); |
| } |
| } |
| return result._types.size(); |
| } |
| |
| } else if (auto FD = dyn_cast<AbstractFunctionDecl>(parent_decl)) { |
| // FIXME: We should not end up here at all. For some reason we're trying |
| // to look up members of a local type inside the parent context of the |
| // local type. |
| // |
| // This code path is broken and is about to be replaced. |
| if (name.isSpecial()) |
| return result._decls.size(); |
| |
| // Do a local lookup into the function, using the end loc to approximate |
| // being able to see all the local variables. |
| // FIXME: Need a more complete/robust lookup mechanism that can handle |
| // declarations in sub-stmts, etc. |
| UnqualifiedLookup lookup(name, FD, ast->getLazyResolver(), |
| FD->getEndLoc()); |
| if (!lookup.isSuccess()) { |
| result._error = "no decl found in function"; |
| } else { |
| for (auto decl : lookup.Results) { |
| auto *VD = decl.getValueDecl(); |
| result._decls.push_back(VD); |
| result._types.push_back(VD->getInterfaceType()); |
| } |
| } |
| return result._decls.size(); |
| |
| } else { |
| result._error = stringWithFormat( |
| "decl is not a nominal_decl (DeclKind=%u), lookup for '%s' failed", |
| (uint32_t)parent_decl->getKind(), |
| name.userFacingName().str().c_str()); |
| } |
| } |
| } else if (result._module) { |
| ModuleDecl::AccessPathTy access_path; |
| SmallVector<ValueDecl *, 4> decls; |
| if (priv_decl_id) |
| result._module.lookupMember( |
| name, ast->getIdentifier(priv_decl_id.getValue().c_str()), decls); |
| else |
| result._module.lookupValue(access_path, name, NLKind::QualifiedLookup, |
| decls); |
| if (decls.empty()) { |
| result._error = |
| stringWithFormat("no decl named '%s' found in module '%s'", |
| name.userFacingName().str().c_str(), |
| result._module.GetName().data()); |
| } else { |
| for (auto decl : decls) { |
| if (decl->hasInterfaceType()) { |
| result._decls.push_back(decl); |
| if (decl->hasInterfaceType()) { |
| result._types.push_back(decl->getInterfaceType()); |
| MetatypeType *meta_type = |
| result._types.back()->getAs<MetatypeType>(); |
| if (meta_type) |
| result._types.back() = meta_type->getInstanceType(); |
| } else { |
| result._types.push_back(Type()); |
| } |
| } |
| } |
| return result._types.size(); |
| } |
| } |
| result.Clear(); |
| result._error = "Generic error."; |
| return false; |
| } |
| |
| static DeclKind GetKindAsDeclKind(Demangle::Node::Kind node_kind) { |
| switch (node_kind) { |
| case Demangle::Node::Kind::TypeAlias: |
| return DeclKind::TypeAlias; |
| case Demangle::Node::Kind::Structure: |
| return DeclKind::Struct; |
| case Demangle::Node::Kind::Class: |
| return DeclKind::Class; |
| case Demangle::Node::Kind::Allocator: |
| return DeclKind::Constructor; |
| case Demangle::Node::Kind::Function: |
| return DeclKind::Func; |
| case Demangle::Node::Kind::Enum: |
| return DeclKind::Enum; |
| case Demangle::Node::Kind::Protocol: |
| return DeclKind::Protocol; |
| case Demangle::Node::Kind::Variable: |
| return DeclKind::Var; |
| default: |
| llvm_unreachable("Missing alias"); |
| } |
| } |
| |
| // This should be called with a function type & its associated Decl. If the |
| // type is not a function type, |
| // then we just return the original type, but we don't check that the Decl is |
| // the associated one. |
| // It is assumed you will get that right in calling this. |
| // Returns a version of the input type with the ExtInfo AbstractCC set |
| // correctly. |
| // This allows CompilerType::IsSwiftMethod to work properly off the swift Type. |
| // FIXME: we don't currently distinguish between Method & Witness. These types |
| // don't actually get used |
| // to make Calling Convention choices - originally we were leaving them all at |
| // Normal... But if we ever |
| // need to set it for that purpose we will have to fix that here. |
| static TypeBase *FixCallingConv(Decl *in_decl, TypeBase *in_type) { |
| if (!in_decl) |
| return in_type; |
| |
| auto *func_type = dyn_cast<AnyFunctionType>(in_type); |
| if (func_type) { |
| DeclContext *decl_context = in_decl->getDeclContext(); |
| if (decl_context && decl_context->isTypeContext()) { |
| // Add the ExtInfo: |
| AnyFunctionType::ExtInfo new_info( |
| func_type->getExtInfo().withSILRepresentation( |
| SILFunctionTypeRepresentation::Method)); |
| return func_type->withExtInfo(new_info); |
| } |
| } |
| return in_type; |
| } |
| |
| static void |
| VisitNode(ASTContext *ast, |
| Demangle::NodePointer node, |
| VisitNodeResult &result); |
| |
| static void VisitNodeAddressor( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| // Addressors are apparently SIL-level functions of the form () -> RawPointer |
| // and they bear no connection to their original variable at the interface |
| // level |
| CanFunctionType swift_can_func_type = |
| CanFunctionType::get(AnyFunctionType::CanParamArrayRef(), |
| ast->TheRawPointerType, |
| AnyFunctionType::ExtInfo()); |
| result._types.push_back(swift_can_func_type.getPointer()); |
| } |
| |
| static void VisitNodeAssociatedTypeRef( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| Demangle::NodePointer root = cur_node->getChild(0); |
| Demangle::NodePointer ident = cur_node->getChild(1); |
| if (!root || !ident) |
| return; |
| VisitNodeResult type_result; |
| VisitNode(ast, root, type_result); |
| if (type_result._types.size() == 1) { |
| TypeBase *type = type_result._types[0].getPointer(); |
| if (type) { |
| ArchetypeType *archetype = type->getAs<ArchetypeType>(); |
| if (archetype) { |
| Identifier identifier = ast->getIdentifier(ident->getText()); |
| Type nested; |
| if (archetype->hasNestedType(identifier)) |
| nested = archetype->getNestedType(identifier); |
| if (nested) { |
| result._types.push_back(nested); |
| result._module = type_result._module; |
| return; |
| } |
| } |
| } |
| } |
| result._types.clear(); |
| result._error = stringWithFormat( |
| "unable to find associated type %s in context", |
| ident->getText().str().c_str()); |
| } |
| |
| static void VisitNodeBoundGeneric( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| if (cur_node->begin() != cur_node->end()) { |
| VisitNodeResult generic_type_result; |
| VisitNodeResult template_types_result; |
| |
| Demangle::Node::iterator end = cur_node->end(); |
| for (Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) { |
| const Demangle::Node::Kind child_node_kind = (*pos)->getKind(); |
| switch (child_node_kind) { |
| case Demangle::Node::Kind::Type: |
| VisitNode(ast, *pos, generic_type_result); |
| break; |
| case Demangle::Node::Kind::TypeList: |
| VisitNode(ast, *pos, template_types_result); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| if (generic_type_result._decls.size() == 1 && |
| generic_type_result._types.size() == 1 && |
| !template_types_result._types.empty()) { |
| auto *nominal_type_decl = |
| cast<NominalTypeDecl>(generic_type_result._decls.front()); |
| auto parent_type = generic_type_result._types.front() |
| ->getNominalParent(); |
| result._types.push_back( |
| BoundGenericType::get( |
| nominal_type_decl, parent_type, template_types_result._types)); |
| result._decls.push_back(nominal_type_decl); |
| } |
| } |
| } |
| |
| static void VisitNodeBuiltinTypeName( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| std::string builtin_name = cur_node->getText(); |
| |
| StringRef builtin_name_ref(builtin_name); |
| |
| if (builtin_name_ref.startswith(BUILTIN_TYPE_NAME_PREFIX)) { |
| StringRef stripped_name_ref = |
| builtin_name_ref.drop_front(strlen(BUILTIN_TYPE_NAME_PREFIX)); |
| SmallVector<ValueDecl *, 1> builtin_decls; |
| |
| result._module = |
| DeclsLookupSource::GetDeclsLookupSource(*ast, ConstString(BUILTIN_NAME)); |
| |
| if (!FindNamedDecls(ast, ast->getIdentifier(stripped_name_ref), result)) { |
| result.Clear(); |
| result._error = stringWithFormat("Couldn't find %s in the builtin module", |
| builtin_name.c_str()); |
| } |
| } else { |
| result._error = stringWithFormat( |
| "BuiltinTypeName %s doesn't start with %s", builtin_name.c_str(), BUILTIN_TYPE_NAME_PREFIX); |
| } |
| } |
| |
| static void VisitNodeConstructor( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| VisitNodeResult kind_type_result; |
| VisitNodeResult type_result; |
| std::vector<StringRef> labels; |
| |
| Demangle::Node::iterator end = cur_node->end(); |
| for (Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) { |
| const Demangle::Node::Kind child_node_kind = (*pos)->getKind(); |
| switch (child_node_kind) { |
| case Demangle::Node::Kind::Enum: |
| case Demangle::Node::Kind::Class: |
| case Demangle::Node::Kind::Structure: |
| VisitNode(ast, *pos, kind_type_result); |
| break; |
| case Demangle::Node::Kind::LabelList: { |
| for (const auto &label : **pos) { |
| if (label->getKind() == Demangle::Node::Kind::FirstElementMarker) |
| labels.push_back(StringRef()); |
| else { |
| labels.push_back(label->getText()); |
| } |
| } |
| break; |
| } |
| case Demangle::Node::Kind::Type: |
| VisitNode(ast, *pos, type_result); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| if (kind_type_result.HasSingleType() && type_result.HasSingleType()) { |
| bool found = false; |
| const size_t n = FindNamedDecls(ast, DeclBaseName::createConstructor(), |
| kind_type_result); |
| if (n == 1) { |
| found = true; |
| kind_type_result._types[0] = FixCallingConv( |
| kind_type_result._decls[0], kind_type_result._types[0].getPointer()); |
| result = kind_type_result; |
| } else if (n > 0) { |
| const size_t num_kind_type_results = kind_type_result._types.size(); |
| for (size_t i = 0; i < num_kind_type_results && !found; ++i) { |
| auto &identifier_type = kind_type_result._types[i]; |
| if (identifier_type && |
| identifier_type->getKind() == |
| type_result._types.front()->getKind()) { |
| // These are the same kind of type, we need to disambiguate them |
| switch (identifier_type->getKind()) { |
| default: |
| break; |
| case TypeKind::Function: { |
| const AnyFunctionType *identifier_func = |
| identifier_type->getAs<AnyFunctionType>(); |
| |
| // inits are typed as (Foo.Type) -> (args...) -> Foo, but don't |
| // assert that in case we're dealing with broken code. |
| if (identifier_func->getInput()->is<AnyMetatypeType>() && |
| identifier_func->getResult()->is<AnyFunctionType>()) { |
| identifier_func = |
| identifier_func->getResult()->getAs<AnyFunctionType>(); |
| } |
| |
| const AnyFunctionType *type_func = |
| type_result._types.front()->getAs<AnyFunctionType>(); |
| |
| if (CompareFunctionTypes(type_func, identifier_func, labels)) { |
| result._module = kind_type_result._module; |
| result._decls.push_back(kind_type_result._decls[i]); |
| result._types.push_back( |
| FixCallingConv(kind_type_result._decls[i], |
| kind_type_result._types[i].getPointer())); |
| found = true; |
| } |
| } break; |
| } |
| } |
| } |
| } |
| // Didn't find a match, just return the raw function type |
| if (!found) |
| result = type_result; |
| } |
| } |
| |
| static void VisitNodeDestructor( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| VisitNodeResult kind_type_result; |
| |
| Demangle::Node::iterator end = cur_node->end(); |
| for (Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) { |
| const Demangle::Node::Kind child_node_kind = (*pos)->getKind(); |
| switch (child_node_kind) { |
| case Demangle::Node::Kind::Enum: |
| case Demangle::Node::Kind::Class: |
| case Demangle::Node::Kind::Structure: |
| VisitNode(ast, *pos, kind_type_result); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| if (kind_type_result.HasSingleType()) { |
| const size_t n = FindNamedDecls(ast, DeclBaseName::createDestructor(), |
| kind_type_result); |
| if (n == 1) { |
| kind_type_result._types[0] = FixCallingConv( |
| kind_type_result._decls[0], kind_type_result._types[0].getPointer()); |
| result = kind_type_result; |
| } else if (n > 0) { |
| // I can't think of a reason why we would get more than one decl called |
| // deinit here, but |
| // just in case, if it is a function type, we should remember it. |
| bool found = false; |
| const size_t num_kind_type_results = kind_type_result._types.size(); |
| for (size_t i = 0; i < num_kind_type_results && !found; ++i) { |
| auto &identifier_type = kind_type_result._types[i]; |
| if (identifier_type) { |
| switch (identifier_type->getKind()) { |
| default: |
| break; |
| case TypeKind::Function: { |
| result._module = kind_type_result._module; |
| result._decls.push_back(kind_type_result._decls[i]); |
| result._types.push_back( |
| FixCallingConv(kind_type_result._decls[i], |
| kind_type_result._types[i].getPointer())); |
| found = true; |
| } break; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| static Demangle::NodePointer DropGenericSignature( |
| Demangle::NodePointer cur_node) { |
| if (cur_node->getKind() != Demangle::Node::Kind::DependentGenericType) |
| return nullptr; |
| if (cur_node->getChild(0) == nullptr) |
| return nullptr; |
| return cur_node->getFirstChild(); |
| } |
| |
| static void VisitNodeDeclContext( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| switch (cur_node->getNumChildren()) { |
| default: |
| result._error = |
| stringWithFormat("DeclContext had %llu children, giving up", |
| (unsigned long long)cur_node->getNumChildren()); |
| break; |
| case 0: |
| result._error = "empty DeclContext unusable"; |
| break; |
| case 1: |
| // nominal type |
| VisitNode(ast, cur_node->getFirstChild(), result); |
| break; |
| case 2: |
| // function type: decl-ctx + type |
| // FIXME: we should just be able to demangle the DeclCtx and resolve the |
| // function |
| // this is fragile and will easily break |
| Demangle::NodePointer path = cur_node->getFirstChild(); |
| VisitNodeResult found_decls; |
| VisitNode(ast, path, found_decls); |
| Demangle::NodePointer generics = cur_node->getChild(1); |
| if (generics->getChild(0) == nullptr) |
| break; |
| generics = generics->getFirstChild(); |
| generics = DropGenericSignature(generics); |
| if (generics == nullptr) |
| break; |
| |
| AbstractFunctionDecl *func_decl = nullptr; |
| for (Decl *decl : found_decls._decls) { |
| func_decl = dyn_cast<AbstractFunctionDecl>(decl); |
| if (!func_decl) |
| continue; |
| GenericParamList *gen_params = func_decl->getGenericParams(); |
| if (!gen_params) |
| continue; |
| } |
| if (func_decl) { |
| result._module = found_decls._module; |
| result._decls.push_back(func_decl); |
| result._types.push_back(func_decl->getInterfaceType().getPointer()); |
| } else |
| result._error = "could not find a matching function for the DeclContext"; |
| break; |
| } |
| } |
| |
| static void VisitNodeExplicitClosure( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| // FIXME: closures are mangled as hanging off a function, but they really |
| // aren't |
| // so we cannot really do a lot about them, other than make a function type |
| // for whatever their advertised type is, and cross fingers |
| VisitNodeResult function_result; |
| VisitNodeResult closure_type_result; |
| VisitNodeResult module_result; |
| Demangle::Node::iterator end = cur_node->end(); |
| for (Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) { |
| const Demangle::Node::Kind child_node_kind = (*pos)->getKind(); |
| switch (child_node_kind) { |
| default: |
| result._error = |
| stringWithFormat("%s encountered in ExplicitClosure children", |
| Demangle::getNodeKindString(child_node_kind)); |
| break; |
| case Demangle::Node::Kind::Module: |
| VisitNode(ast, *pos, module_result); |
| break; |
| case Demangle::Node::Kind::Function: |
| VisitNode(ast, *pos, function_result); |
| break; |
| case Demangle::Node::Kind::Number: |
| break; |
| case Demangle::Node::Kind::Type: |
| VisitNode(ast, *pos, closure_type_result); |
| break; |
| } |
| } |
| if (closure_type_result.HasSingleType()) |
| result._types.push_back(closure_type_result._types.front()); |
| else |
| result._error = "multiple potential candidates to be this closure's type"; |
| // FIXME: closures are not lookupable by compiler team's decision |
| // ("You cannot perform lookup into local contexts." x3) |
| // so we at least store the module the closure came from to enable |
| // further local types lookups |
| if (module_result._module) |
| result._module = module_result._module; |
| } |
| |
| static void VisitNodeExtension( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| VisitNodeResult module_result; |
| VisitNodeResult type_result; |
| std::string error; |
| Demangle::Node::iterator end = cur_node->end(); |
| for (Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) { |
| const Demangle::Node::Kind child_node_kind = (*pos)->getKind(); |
| switch (child_node_kind) { |
| default: |
| result._error = |
| stringWithFormat("%s encountered in extension children", |
| Demangle::getNodeKindString(child_node_kind)); |
| break; |
| |
| case Demangle::Node::Kind::Module: |
| VisitNode(ast, *pos, module_result); |
| break; |
| |
| case Demangle::Node::Kind::Class: |
| case Demangle::Node::Kind::Enum: |
| case Demangle::Node::Kind::Structure: |
| case Demangle::Node::Kind::Protocol: |
| VisitNode(ast, *pos, type_result); |
| break; |
| } |
| } |
| |
| if (module_result._module) { |
| if (type_result._decls.size() == 1) { |
| Decl *decl = type_result._decls[0]; |
| NominalTypeDecl *nominal_decl = dyn_cast_or_null<NominalTypeDecl>(decl); |
| if (nominal_decl) { |
| result._module = DeclsLookupSource::GetDeclsLookupSource( |
| module_result._module, nominal_decl); |
| } else |
| result._error = "unable to find nominal type for extension"; |
| } else |
| result._error = "unable to find unique type for extension"; |
| } else |
| result._error = "unable to find module name for extension"; |
| } |
| |
| static bool AreBothFunctionTypes(TypeKind a, TypeKind b) { |
| bool is_first = false, is_second = false; |
| if (a >= TypeKind::First_AnyFunctionType && |
| a <= TypeKind::Last_AnyFunctionType) |
| is_first = true; |
| if (b >= TypeKind::First_AnyFunctionType && |
| b <= TypeKind::Last_AnyFunctionType) |
| is_second = true; |
| return (is_first && is_second); |
| } |
| |
| static bool CompareFunctionTypes(const AnyFunctionType *f, |
| const AnyFunctionType *g, |
| Optional<std::vector<StringRef>> fLabels, |
| Optional<std::vector<StringRef>> gLabels, |
| bool *input_matches, bool *output_matches) { |
| if (nullptr == f) |
| return (nullptr == g); |
| if (nullptr == g) |
| return false; |
| |
| auto getLabel = [&](Optional<std::vector<StringRef>> labels, |
| AnyFunctionType::Param ¶m, |
| unsigned index) -> StringRef { |
| return (labels && labels->size() > index) ? (*labels)[index] |
| : param.getLabel().str(); |
| }; |
| |
| auto params1 = f->getParams(); |
| auto params2 = g->getParams(); |
| |
| bool in_matches = params1.size() == params2.size(), out_matches = true; |
| auto numParams = std::min(params2.size(), params1.size()); |
| |
| for (unsigned i = 0; i != numParams; ++i) { |
| auto param1 = params1[i]; |
| auto param2 = params2[i]; |
| |
| auto label1 = getLabel(fLabels, param1, i); |
| auto label2 = getLabel(gLabels, param2, i); |
| |
| if (label1.equals(label2) && param1.getType()->isEqual(param2.getType())) |
| continue; |
| |
| in_matches = false; |
| break; |
| } |
| |
| out_matches = f->getResult()->isEqual(g->getResult()); |
| |
| if (input_matches) |
| *input_matches = in_matches; |
| if (output_matches) |
| *output_matches = out_matches; |
| |
| return (in_matches && out_matches); |
| } |
| |
| static void VisitNodePrivateDeclName( |
| ASTContext *ast, |
| Demangle::NodePointer parent_node, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| DeclKind decl_kind = GetKindAsDeclKind(parent_node->getKind()); |
| |
| if (cur_node->getNumChildren() != 2) { |
| if (result._error.empty()) |
| result._error = stringWithFormat( |
| "unable to retrieve content for Node::Kind::PrivateDeclName"); |
| return; |
| } |
| |
| Demangle::NodePointer priv_decl_id_node(cur_node->getChild(0)); |
| Demangle::NodePointer id_node(cur_node->getChild(1)); |
| |
| if (!priv_decl_id_node->hasText() || !id_node->hasText()) { |
| if (result._error.empty()) |
| result._error = stringWithFormat( |
| "unable to retrieve content for Node::Kind::PrivateDeclName"); |
| return; |
| } |
| |
| if (!FindFirstNamedDeclWithKind(ast, ast->getIdentifier(id_node->getText()), |
| decl_kind, result, |
| priv_decl_id_node->getText().str())) { |
| if (result._error.empty()) |
| result._error = stringWithFormat( |
| "unable to find Node::Kind::PrivateDeclName '%s' in '%s'", |
| id_node->getText().str().c_str(), |
| priv_decl_id_node->getText().str().c_str()); |
| } |
| } |
| |
| static void VisitLocalDeclVariableName(ASTContext *ast, |
| Demangle::NodePointer child, |
| VisitNodeResult &result) { |
| if (child->getNumChildren() != 2 || !child->getChild(1)->hasText()) { |
| if (result._error.empty()) |
| result._error = |
| "unable to retrieve content for Node::Kind::LocalDeclName"; |
| return; |
| } |
| |
| auto name = child->getChild(1); |
| FindNamedDecls(ast, ast->getIdentifier(name->getText()), result); |
| if (result._decls.empty()) |
| result._error = stringWithFormat( |
| "demangled identifier '%s' could not be found by name lookup", |
| name->getText()); |
| } |
| |
| // VisitNodeFunction gets used for Function and Variable. |
| static void VisitNodeFunction( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| VisitNodeResult identifier_result; |
| VisitNodeResult type_result; |
| VisitNodeResult decl_scope_result; |
| std::vector<StringRef> labels; |
| |
| Demangle::Node::iterator end = cur_node->end(); |
| bool found_univocous = false; |
| for (Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) { |
| if (found_univocous) |
| break; |
| auto child = *pos; |
| const Demangle::Node::Kind child_node_kind = child->getKind(); |
| switch (child_node_kind) { |
| default: |
| result._error = |
| stringWithFormat("%s encountered in function children", |
| Demangle::getNodeKindString(child_node_kind)); |
| break; |
| |
| // TODO: any other possible containers? |
| case Demangle::Node::Kind::Function: |
| case Demangle::Node::Kind::Class: |
| case Demangle::Node::Kind::Enum: |
| case Demangle::Node::Kind::Module: |
| case Demangle::Node::Kind::Structure: |
| case Demangle::Node::Kind::Protocol: |
| case Demangle::Node::Kind::Extension: |
| VisitNode(ast, *pos, decl_scope_result); |
| break; |
| |
| case Demangle::Node::Kind::PrivateDeclName: { |
| VisitNodePrivateDeclName(ast, cur_node, child, decl_scope_result); |
| |
| // No results found, giving up. |
| if (decl_scope_result._decls.empty()) |
| break; |
| |
| std::copy(decl_scope_result._decls.begin(), |
| decl_scope_result._decls.end(), |
| back_inserter(identifier_result._decls)); |
| std::copy(decl_scope_result._types.begin(), |
| decl_scope_result._types.end(), |
| back_inserter(identifier_result._types)); |
| identifier_result._module = decl_scope_result._module; |
| if (decl_scope_result._decls.size() == 1) |
| found_univocous = true; |
| break; |
| } |
| |
| case Demangle::Node::Kind::LabelList: { |
| for (const auto &label : **pos) { |
| if (label->getKind() == Demangle::Node::Kind::FirstElementMarker) |
| labels.push_back(StringRef()); |
| else { |
| labels.push_back(label->getText()); |
| } |
| } |
| break; |
| } |
| |
| case Demangle::Node::Kind::LocalDeclName: { |
| VisitLocalDeclVariableName(ast, child, decl_scope_result); |
| if (decl_scope_result._decls.empty()) |
| break; |
| std::copy(decl_scope_result._decls.begin(), |
| decl_scope_result._decls.end(), |
| back_inserter(identifier_result._decls)); |
| std::copy(decl_scope_result._types.begin(), |
| decl_scope_result._types.end(), |
| back_inserter(identifier_result._types)); |
| identifier_result._module = decl_scope_result._module; |
| if (decl_scope_result._decls.size() == 1) |
| found_univocous = true; |
| break; |
| } |
| case Demangle::Node::Kind::Identifier: |
| case Demangle::Node::Kind::InfixOperator: |
| case Demangle::Node::Kind::PrefixOperator: |
| case Demangle::Node::Kind::PostfixOperator: |
| FindNamedDecls(ast, ast->getIdentifier((*pos)->getText()), |
| decl_scope_result); |
| if (decl_scope_result._decls.empty()) { |
| result._error = stringWithFormat( |
| "demangled identifier %s could not be found by name lookup", |
| (*pos)->getText().str().c_str()); |
| break; |
| } |
| std::copy(decl_scope_result._decls.begin(), |
| decl_scope_result._decls.end(), |
| back_inserter(identifier_result._decls)); |
| std::copy(decl_scope_result._types.begin(), |
| decl_scope_result._types.end(), |
| back_inserter(identifier_result._types)); |
| identifier_result._module = decl_scope_result._module; |
| if (decl_scope_result._decls.size() == 1) |
| found_univocous = true; |
| break; |
| |
| case Demangle::Node::Kind::Type: |
| VisitNode(ast, *pos, type_result); |
| break; |
| } |
| } |
| |
| do { |
| if (cur_node->getKind() == Demangle::Node::Kind::Subscript) { |
| FindNamedDecls(ast, DeclBaseName::createSubscript(), |
| decl_scope_result); |
| if (decl_scope_result._decls.empty()) { |
| result._error = stringWithFormat( |
| "subscript identifier could not be found by name lookup"); |
| break; |
| } |
| std::copy(decl_scope_result._decls.begin(), |
| decl_scope_result._decls.end(), |
| back_inserter(identifier_result._decls)); |
| std::copy(decl_scope_result._types.begin(), |
| decl_scope_result._types.end(), |
| back_inserter(identifier_result._types)); |
| identifier_result._module = decl_scope_result._module; |
| if (decl_scope_result._decls.size() == 1) |
| found_univocous = true; |
| break; |
| } |
| } while (0); |
| |
| if (identifier_result._types.size() == 1) { |
| result._module = identifier_result._module; |
| result._decls.push_back(identifier_result._decls[0]); |
| result._types.push_back(FixCallingConv( |
| identifier_result._decls[0], identifier_result._types[0].getPointer())); |
| } else if (type_result.HasSingleType()) { |
| const size_t num_identifier_results = identifier_result._types.size(); |
| bool found = false; |
| for (size_t i = 0; i < num_identifier_results && !found; ++i) { |
| auto &identifier_type = identifier_result._types[i]; |
| if (!identifier_type) |
| continue; |
| if (AreBothFunctionTypes(identifier_type->getKind(), |
| type_result._types.front()->getKind())) { |
| const AnyFunctionType *identifier_func = |
| identifier_type->getAs<AnyFunctionType>(); |
| const AnyFunctionType *type_func = |
| type_result._types.front()->getAs<AnyFunctionType>(); |
| if (CompareFunctionTypes(type_func, identifier_func, labels)) { |
| result._module = identifier_result._module; |
| result._decls.push_back(identifier_result._decls[i]); |
| result._types.push_back( |
| FixCallingConv(identifier_result._decls[i], |
| identifier_result._types[i].getPointer())); |
| found = true; |
| } |
| } |
| } |
| // Didn't find a match, just return the raw function type |
| if (!found) |
| result = type_result; |
| } |
| } |
| |
| static void CreateFunctionType(ASTContext *ast, |
| const VisitNodeResult &arg_type_result, |
| const VisitNodeResult &return_type_result, |
| bool escaping, |
| bool throws, |
| VisitNodeResult &result) { |
| Type arg_clang_type; |
| Type return_clang_type; |
| |
| switch (arg_type_result._types.size()) { |
| case 0: |
| arg_clang_type = TupleType::getEmpty(*ast); |
| break; |
| case 1: |
| arg_clang_type = arg_type_result._types.front().getPointer(); |
| break; |
| default: |
| result._error = "too many argument types for a function type"; |
| break; |
| } |
| |
| switch (return_type_result._types.size()) { |
| case 0: |
| return_clang_type = TupleType::getEmpty(*ast); |
| break; |
| case 1: |
| return_clang_type = return_type_result._types.front().getPointer(); |
| break; |
| default: |
| result._error = "too many return types for a function type"; |
| break; |
| } |
| |
| if (arg_clang_type && return_clang_type) { |
| result._types.push_back( |
| FunctionType::get(arg_clang_type, return_clang_type, |
| FunctionType::ExtInfo().withNoEscape(!escaping) |
| .withThrows(throws))); |
| } |
| } |
| |
| static void VisitNodeFunctionType( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| VisitNodeResult arg_type_result; |
| VisitNodeResult return_type_result; |
| Demangle::Node::iterator end = cur_node->end(); |
| bool throws = false; |
| for (Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) { |
| const Demangle::Node::Kind child_node_kind = (*pos)->getKind(); |
| switch (child_node_kind) { |
| case Demangle::Node::Kind::ArgumentTuple: |
| VisitNode(ast, *pos, arg_type_result); |
| break; |
| case Demangle::Node::Kind::ThrowsAnnotation: |
| throws = true; |
| break; |
| case Demangle::Node::Kind::ReturnType: |
| VisitNode(ast, *pos, return_type_result); |
| break; |
| default: |
| break; |
| } |
| } |
| CreateFunctionType(ast, arg_type_result, return_type_result, |
| cur_node->getKind() == Demangle::Node::Kind::FunctionType, |
| throws, result); |
| } |
| |
| static void VisitNodeImplFunctionType( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| VisitNodeResult arg_type_result; |
| VisitNodeResult return_type_result; |
| Demangle::Node::iterator end = cur_node->end(); |
| bool escaping = false; |
| bool throws = false; |
| for (Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) { |
| const Demangle::Node::Kind child_node_kind = (*pos)->getKind(); |
| switch (child_node_kind) { |
| case Demangle::Node::Kind::ImplEscaping: |
| escaping = true; |
| break; |
| case Demangle::Node::Kind::ImplConvention: |
| // Ignore the ImplConvention it is only a hint for the SIL ARC optimizer. |
| break; |
| case Demangle::Node::Kind::ImplParameter: |
| VisitNode(ast, *pos, arg_type_result); |
| break; |
| case Demangle::Node::Kind::ThrowsAnnotation: |
| throws = true; |
| break; |
| case Demangle::Node::Kind::ImplResult: |
| VisitNode(ast, *pos, return_type_result); |
| break; |
| default: |
| break; |
| } |
| } |
| CreateFunctionType(ast, arg_type_result, return_type_result, escaping, throws, |
| result); |
| } |
| |
| |
| static void VisitNodeSetterGetter( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| VisitNodeResult decl_ctx_result; |
| std::string identifier; |
| std::vector<StringRef> labels; |
| |
| VisitNodeResult type_result; |
| |
| assert(cur_node->getNumChildren() == 1 && |
| "Accessor should have a single abstract storage child"); |
| Demangle::NodePointer referenced_node = cur_node->getFirstChild(); |
| assert((referenced_node->getKind() == Demangle::Node::Kind::Variable || |
| referenced_node->getKind() == Demangle::Node::Kind::Subscript) && |
| "Accessor child should be a storage node"); |
| |
| Demangle::Node::Kind node_kind = cur_node->getKind(); |
| |
| for (Demangle::Node::iterator pos = referenced_node->begin(), |
| end = referenced_node->end(); |
| pos != end; ++pos) { |
| const Demangle::Node::Kind child_node_kind = (*pos)->getKind(); |
| switch (child_node_kind) { |
| case Demangle::Node::Kind::Class: |
| case Demangle::Node::Kind::Module: |
| case Demangle::Node::Kind::Structure: |
| VisitNode(ast, *pos, decl_ctx_result); |
| break; |
| case Demangle::Node::Kind::Identifier: |
| identifier.assign((*pos)->getText()); |
| break; |
| case Demangle::Node::Kind::Type: { |
| auto type = (*pos)->getFirstChild(); |
| if (DropGenericSignature(type)) |
| type = type->getChild(1); |
| VisitNode(ast, type, type_result); |
| break; |
| } |
| case Demangle::Node::Kind::LabelList: { |
| for (const auto &label : **pos) { |
| if (label->getKind() == Demangle::Node::Kind::FirstElementMarker) |
| labels.push_back(StringRef()); |
| else { |
| labels.push_back(label->getText()); |
| } |
| } |
| break; |
| } |
| default: |
| result._error = |
| stringWithFormat("%s encountered in generic type children", |
| Demangle::getNodeKindString(child_node_kind)); |
| break; |
| } |
| } |
| |
| if (!type_result.HasSingleType()) { |
| result._error = "bad type"; |
| return; |
| } |
| |
| if (referenced_node->getKind() == Demangle::Node::Kind::Subscript) { |
| // Since there can be many subscripts for the same nominal type, we need to |
| // find the one matching the specified type. |
| |
| FindNamedDecls(ast, DeclBaseName::createSubscript(), decl_ctx_result); |
| size_t num_decls = decl_ctx_result._decls.size(); |
| |
| if (num_decls == 0) { |
| result._error = "Could not find a subscript decl"; |
| return; |
| } |
| |
| SubscriptDecl *subscript_decl; |
| const AnyFunctionType *type_func = |
| type_result._types.front()->getAs<AnyFunctionType>(); |
| |
| FuncDecl *identifier_func = nullptr; |
| |
| for (size_t i = 0; i < num_decls; i++) { |
| subscript_decl = |
| dyn_cast_or_null<SubscriptDecl>(decl_ctx_result._decls[i]); |
| if (subscript_decl) { |
| switch (node_kind) { |
| case Demangle::Node::Kind::Getter: |
| identifier_func = subscript_decl->getGetter(); |
| break; |
| case Demangle::Node::Kind::Setter: |
| identifier_func = subscript_decl->getSetter(); |
| break; |
| case Demangle::Node::Kind::DidSet: |
| identifier_func = subscript_decl->getDidSetFunc(); |
| break; |
| case Demangle::Node::Kind::WillSet: |
| identifier_func = subscript_decl->getWillSetFunc(); |
| break; |
| default: |
| identifier_func = nullptr; |
| break; |
| } |
| |
| if (identifier_func && |
| subscript_decl->getGetter() && |
| subscript_decl->getGetter()->getInterfaceType()) { |
| auto subscript_type = |
| subscript_decl->getGetter()->getInterfaceType()->getAs<AnyFunctionType>(); |
| |
| if (subscript_type) { |
| // Swift function types are formally functions that take the class |
| // and return the method, |
| // we have to strip off the first level of function call to compare |
| // against the type |
| // from the demangled name. |
| auto subscript_uncurried_result = |
| subscript_type->getResult()->getAs<AnyFunctionType>(); |
| if (subscript_uncurried_result) { |
| if (CompareFunctionTypes(type_func, |
| subscript_uncurried_result, |
| labels)) { |
| break; |
| } |
| } |
| } |
| } |
| } |
| identifier_func = nullptr; |
| } |
| |
| if (identifier_func) { |
| result._decls.push_back(identifier_func); |
| result._types.push_back(FixCallingConv( |
| identifier_func, identifier_func->getInterfaceType().getPointer())); |
| } else { |
| result._error = "could not find a matching subscript signature"; |
| } |
| } else { |
| // Otherwise this is a getter/setter/etc for a variable. Currently you |
| // can't write a getter/setter that |
| // takes a different type from the type of the variable. So there is only |
| // one possible function. |
| AbstractStorageDecl *var_decl = nullptr; |
| |
| FindFirstNamedDeclWithKind(ast, ast->getIdentifier(identifier), |
| DeclKind::Var, decl_ctx_result); |
| |
| if (decl_ctx_result._decls.size() == 1) { |
| var_decl = dyn_cast_or_null<VarDecl>(decl_ctx_result._decls[0]); |
| } else if (!decl_ctx_result._decls.empty()) { |
| // TODO: can we use the type to pick the right one? can we really have |
| // multiple variables with the same name? |
| result._error = stringWithFormat( |
| "multiple variables with the same name %s", identifier.c_str()); |
| return; |
| } else { |
| result._error = |
| stringWithFormat("no variables with the name %s", identifier.c_str()); |
| return; |
| } |
| |
| if (var_decl) { |
| FuncDecl *decl = nullptr; |
| |
| if (node_kind == Demangle::Node::Kind::DidSet && |
| var_decl->getDidSetFunc()) { |
| decl = var_decl->getDidSetFunc(); |
| } else if (node_kind == Demangle::Node::Kind::Getter && |
| var_decl->getGetter()) { |
| decl = var_decl->getGetter(); |
| } else if (node_kind == Demangle::Node::Kind::Setter && |
| var_decl->getSetter()) { |
| decl = var_decl->getSetter(); |
| } else if (node_kind == Demangle::Node::Kind::WillSet && |
| var_decl->getWillSetFunc()) { |
| decl = var_decl->getWillSetFunc(); |
| } |
| |
| if (decl) { |
| result._decls.push_back(decl); |
| result._types.push_back( |
| FixCallingConv(decl, decl->getInterfaceType().getPointer())); |
| } else { |
| result._error = stringWithFormat( |
| "could not retrieve %s for variable %s", |
| Demangle::getNodeKindString(node_kind), |
| identifier.c_str()); |
| return; |
| } |
| } else { |
| result._error = |
| stringWithFormat("no decl object for %s", identifier.c_str()); |
| return; |
| } |
| } |
| } |
| |
| static void VisitNodeIdentifier( |
| ASTContext *ast, |
| Demangle::NodePointer parent_node, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| DeclKind decl_kind = GetKindAsDeclKind(parent_node->getKind()); |
| |
| if (!FindFirstNamedDeclWithKind(ast, ast->getIdentifier(cur_node->getText()), |
| decl_kind, result)) { |
| if (result._error.empty()) |
| result._error = |
| stringWithFormat("unable to find Node::Kind::Identifier '%s'", |
| cur_node->getText().str().c_str()); |
| } |
| } |
| |
| static void VisitNodeLocalDeclName( |
| ASTContext *ast, |
| Demangle::NodePointer parent_node, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| std::string remangledNode = Demangle::mangleNode(parent_node); |
| TypeDecl *decl = result._module.lookupLocalType(remangledNode); |
| if (!decl) |
| result._error = stringWithFormat("unable to lookup local type %s", |
| remangledNode.c_str()); |
| else { |
| // if this were to come from a closure, there may be no decl - just a module |
| if (!result._decls.empty()) |
| result._decls.pop_back(); |
| if (!result._types.empty()) |
| result._types.pop_back(); |
| |
| result._decls.push_back(decl); |
| auto type = decl->getDeclaredInterfaceType(); |
| result._types.push_back(type); |
| } |
| } |
| |
| static void VisitNodeRelatedEntityDeclName( |
| ASTContext *ast, |
| Demangle::NodePointer parent_node, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| DeclKind decl_kind = GetKindAsDeclKind(parent_node->getKind()); |
| |
| if (cur_node->getNumChildren() != 1 || !cur_node->hasText()) { |
| if (result._error.empty()) |
| result._error = stringWithFormat( |
| "unable to retrieve content for Node::Kind::RelatedEntityDeclName"); |
| return; |
| } |
| |
| Demangle::NodePointer id_node(cur_node->getChild(0)); |
| |
| if (!id_node->hasText()) { |
| if (result._error.empty()) |
| result._error = stringWithFormat( |
| "unable to retrieve content for Node::Kind::RelatedEntityDeclName"); |
| return; |
| } |
| |
| SmallVector<ValueDecl *, 4> decls; |
| if (result._module) { |
| result._module.lookupRelatedEntity(id_node->getText(), cur_node->getText(), |
| decl_kind, decls); |
| } |
| |
| if (!FilterDeclsForKind(decl_kind, decls, result)) { |
| if (result._error.empty()) |
| result._error = stringWithFormat( |
| "unable to find Node::Kind::RelatedEntityDeclName '%s' for '%s'", |
| cur_node->getText().str().c_str(), |
| id_node->getText().str().c_str()); |
| return; |
| } |
| } |
| |
| static void VisitNodeNominal( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| Type parent_type; |
| |
| Demangle::Node::iterator child_end = cur_node->end(); |
| for (Demangle::Node::iterator child_pos = cur_node->begin(); |
| child_pos != child_end; ++child_pos) { |
| auto child = *child_pos; |
| switch(child->getKind()) { |
| case Demangle::Node::Kind::Identifier: |
| VisitNodeIdentifier(ast, cur_node, child, result); |
| break; |
| case Demangle::Node::Kind::LocalDeclName: |
| VisitNodeLocalDeclName(ast, cur_node, child, result); |
| break; |
| case Demangle::Node::Kind::PrivateDeclName: |
| VisitNodePrivateDeclName(ast, cur_node, child, result); |
| break; |
| case Demangle::Node::Kind::RelatedEntityDeclName: |
| VisitNodeRelatedEntityDeclName(ast, cur_node, child, result); |
| break; |
| default: |
| VisitNode(ast, child, result); |
| if (result._types.size() == 1) |
| parent_type = result._types.front(); |
| break; |
| } |
| } |
| |
| if (parent_type && |
| parent_type->getAnyNominal() && |
| result._decls.size() == 1 && |
| result._types.size() == 1) { |
| auto nominal_type_decl = cast<NominalTypeDecl>(result._decls.front()); |
| auto subMap = parent_type->getMemberSubstitutionMap( |
| nominal_type_decl->getParentModule(), nominal_type_decl); |
| |
| result._types[0] = result._types[0].subst(subMap); |
| } |
| } |
| |
| static void VisitNodeTypeAlias( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| Type parent_type; |
| |
| Demangle::Node::iterator child_end = cur_node->end(); |
| for (Demangle::Node::iterator child_pos = cur_node->begin(); |
| child_pos != child_end; ++child_pos) { |
| auto child = *child_pos; |
| switch(child->getKind()) { |
| case Demangle::Node::Kind::Identifier: |
| VisitNodeIdentifier(ast, cur_node, child, result); |
| break; |
| case Demangle::Node::Kind::LocalDeclName: |
| VisitNodeLocalDeclName(ast, cur_node, child, result); |
| break; |
| case Demangle::Node::Kind::PrivateDeclName: |
| VisitNodePrivateDeclName(ast, cur_node, child, result); |
| break; |
| case Demangle::Node::Kind::RelatedEntityDeclName: |
| VisitNodeRelatedEntityDeclName(ast, cur_node, child, result); |
| break; |
| default: |
| VisitNode(ast, child, result); |
| break; |
| } |
| } |
| } |
| |
| static void VisitNodeInOut( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| VisitNodeResult type_result; |
| VisitNode(ast, cur_node->getFirstChild(), type_result); |
| if (type_result._types.size() == 1 && type_result._types[0]) { |
| result._types.push_back(InOutType::get(type_result._types[0])); |
| } else { |
| result._error = "couldn't resolve referent type"; |
| } |
| } |
| |
| static void VisitNodeExistentialMetatype(ASTContext *ast, |
| Demangle::NodePointer cur_node, |
| VisitNodeResult &result) { |
| VisitNodeResult type_result; |
| Optional<MetatypeRepresentation> metatype_repr; |
| |
| for (auto &child : *cur_node) { |
| switch (child->getKind()) { |
| case Demangle::Node::Kind::Type: |
| VisitNode(ast, child, type_result); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| if (type_result.HasSingleType()) |
| result._types.push_back( |
| ExistentialMetatypeType::get(type_result._types[0], metatype_repr)); |
| else |
| result._error = stringWithFormat( |
| "instance type for existential metatype cannot be uniquely resolved"); |
| } |
| |
| static void VisitNodeMetatype( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| auto iter = cur_node->begin(); |
| auto end = cur_node->end(); |
| |
| Optional<MetatypeRepresentation> metatype_repr; |
| VisitNodeResult type_result; |
| |
| for (; iter != end; ++iter) { |
| switch ((*iter)->getKind()) { |
| case Demangle::Node::Kind::Type: |
| VisitNode(ast, *iter, type_result); |
| break; |
| case Demangle::Node::Kind::MetatypeRepresentation: |
| if ((*iter)->getText() == "@thick") |
| metatype_repr = MetatypeRepresentation::Thick; |
| else if ((*iter)->getText() == "@thin") |
| metatype_repr = MetatypeRepresentation::Thin; |
| else if ((*iter)->getText() == "@objc") |
| metatype_repr = MetatypeRepresentation::ObjC; |
| else |
| ; // leave it alone if we don't understand the representation |
| break; |
| default: |
| break; |
| } |
| } |
| |
| if (type_result.HasSingleType()) { |
| result._types.push_back( |
| MetatypeType::get(type_result._types[0], metatype_repr)); |
| } else { |
| result._error = stringWithFormat( |
| "instance type for metatype cannot be uniquely resolved"); |
| return; |
| } |
| } |
| |
| static void VisitNodeModule( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| std::string error; |
| StringRef module_name = cur_node->getText(); |
| if (module_name.empty()) { |
| result._error = stringWithFormat("error: empty module name."); |
| return; |
| } |
| |
| result._module = DeclsLookupSource::GetDeclsLookupSource(*ast, |
| ConstString(module_name.str())); |
| if (!result._module) { |
| result._error = stringWithFormat("unable to load module '%s' (%s)", |
| module_name.str().c_str(), error.data()); |
| } |
| } |
| |
| static void VisitNodeTuple( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| if (cur_node->begin() == cur_node->end()) { |
| // No children of this tuple, make an empty tuple |
| |
| result._types.push_back(TupleType::getEmpty(*ast)); |
| } else { |
| std::vector<TupleTypeElt> tuple_fields; |
| Demangle::Node::iterator end = cur_node->end(); |
| for (Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) { |
| VisitNodeResult tuple_element_result; |
| VisitNode(ast, *pos, tuple_element_result); |
| if (tuple_element_result._error.empty() && |
| tuple_element_result._tuple_type_element.getType()) { |
| tuple_fields.push_back(tuple_element_result._tuple_type_element); |
| } else { |
| result._error = tuple_element_result._error; |
| } |
| } |
| if (result._error.empty()) { |
| result._types.push_back(TupleType::get(tuple_fields, *ast)); |
| } |
| } |
| } |
| |
| static void VisitNodeProtocolList( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| if (cur_node->begin() != cur_node->end()) { |
| VisitNodeResult protocol_types_result; |
| VisitNode(ast, cur_node->getFirstChild(), protocol_types_result); |
| if (protocol_types_result._error.empty()) { |
| result._types.push_back( |
| ProtocolCompositionType::get(*ast, protocol_types_result._types, |
| /*HasExplicitAnyObject=*/false)); |
| } |
| } |
| } |
| |
| static void VisitNodeProtocolListWithClass( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| if (cur_node->begin() != cur_node->end()) { |
| VisitNodeResult class_type_result; |
| VisitNodeResult protocol_types_result; |
| Demangle::Node::iterator child_end = cur_node->end(); |
| for (Demangle::Node::iterator child_pos = cur_node->begin(); |
| child_pos != child_end; ++child_pos) { |
| auto child = *child_pos; |
| switch(child->getKind()) { |
| case Demangle::Node::Kind::ProtocolList: |
| VisitNode(ast, child, protocol_types_result); |
| break; |
| case Demangle::Node::Kind::Type: |
| VisitNode(ast, child, class_type_result); |
| break; |
| default: |
| result._error = "invalid subclass existential"; |
| break; |
| } |
| } |
| |
| if (protocol_types_result._error.empty() && |
| !protocol_types_result._types.empty() && |
| class_type_result._types.size() == 1) { |
| SmallVector<Type, 2> members; |
| members.push_back(class_type_result._types.front()); |
| for (auto member : protocol_types_result._types) |
| members.push_back(member); |
| result._types.push_back( |
| ProtocolCompositionType::get(*ast, members, |
| /*HasExplicitAnyObject=*/false)); |
| } |
| } |
| } |
| |
| static void VisitNodeProtocolListWithAnyObject( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| if (cur_node->begin() != cur_node->end()) { |
| VisitNodeResult protocol_types_result; |
| VisitNode(ast, cur_node->getFirstChild(), protocol_types_result); |
| if (protocol_types_result._error.empty()) { |
| result._types.push_back( |
| ProtocolCompositionType::get(*ast, protocol_types_result._types, |
| /*HasExplicitAnyObject=*/true)); |
| } |
| } |
| } |
| |
| static void VisitNodeQualifiedArchetype( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| if (cur_node->begin() != cur_node->end()) { |
| VisitNodeResult type_result; |
| uint64_t index = 0xFFFFFFFFFFFFFFFF; |
| for (Demangle::NodePointer ChildNd : *cur_node) { |
| switch (ChildNd->getKind()) { |
| case Demangle::Node::Kind::Number: |
| index = ChildNd->getIndex(); |
| break; |
| case Demangle::Node::Kind::DeclContext: |
| VisitNode(ast, ChildNd, type_result); |
| break; |
| default: |
| break; |
| } |
| } |
| if (index != 0xFFFFFFFFFFFFFFFF) { |
| Decl *decl_ptr = nullptr; |
| if (type_result._decls.size() == 1) { |
| decl_ptr = type_result._decls[0]; |
| } else if (type_result._module.IsExtension()) { |
| decl_ptr = type_result._module.GetExtendedDecl(); |
| } |
| |
| if (decl_ptr) { |
| auto *dc = decl_ptr->getInnermostDeclContext(); |
| auto *sig = dc->getGenericSignatureOfContext(); |
| if (sig) { |
| auto params = sig->getInnermostGenericParams(); |
| if (index < params.size()) { |
| auto argTy = dc->mapTypeIntoContext(params[index]) |
| ->getAs<ArchetypeType>(); |
| if (argTy) |
| result._types.push_back(argTy); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| static void VisitNodeTupleElement( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| StringRef tuple_name; |
| VisitNodeResult tuple_type_result; |
| Demangle::Node::iterator end = cur_node->end(); |
| for (Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) { |
| const Demangle::Node::Kind child_node_kind = (*pos)->getKind(); |
| switch (child_node_kind) { |
| case Demangle::Node::Kind::TupleElementName: |
| tuple_name = (*pos)->getText(); |
| break; |
| case Demangle::Node::Kind::Type: |
| VisitNode(ast, *pos, tuple_type_result); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| if (!tuple_type_result._error.empty() || tuple_type_result._types.size() != 1) |
| return; |
| |
| auto tupleType = tuple_type_result._types.front(); |
| auto typeFlags = ParameterTypeFlags(); |
| typeFlags = typeFlags.withInOut(tupleType->is<InOutType>()); |
| if (auto *inOutTy = tupleType->getAs<InOutType>()) |
| tupleType = inOutTy->getObjectType(); |
| Identifier idName = |
| tuple_name.empty() ? Identifier() : ast->getIdentifier(tuple_name); |
| result._tuple_type_element = TupleTypeElt(tupleType, idName, typeFlags); |
| } |
| |
| static void VisitNodeTypeList( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| if (cur_node->begin() != cur_node->end()) { |
| Demangle::Node::iterator end = cur_node->end(); |
| for (Demangle::Node::iterator pos = cur_node->begin(); pos != end; ++pos) { |
| VisitNodeResult type_result; |
| VisitNode(ast, *pos, type_result); |
| if (type_result._error.empty() && type_result._types.size() == 1) { |
| if (type_result._decls.empty()) |
| result._decls.push_back(nullptr); |
| else |
| result._decls.push_back(type_result._decls.front()); |
| result._types.push_back(type_result._types.front()); |
| } else { |
| // If we run into any errors parsing getting any types for a type list |
| // we need to bail out and return an error. We have cases where a |
| // private |
| // typealias was used in a mangled variable name. The private typealias |
| // are not included in the modules that are available to the debugger. |
| // This was contained inside of a bound generic structure type that was |
| // expecting two types. If we don't bail out, we end up filling in just |
| // one type in "result" instead of two and then the compiler will crash |
| // later when it tries to create the bound generic from only 1 type. |
| result.Clear(); |
| result._error = type_result._error; |
| break; |
| } |
| } |
| } |
| } |
| |
| static void VisitNodeUnowned( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| VisitNodeResult type_result; |
| VisitNode(ast, cur_node->getFirstChild(), type_result); |
| if (type_result._types.size() == 1 && type_result._types[0]) { |
| result._types.push_back( |
| UnownedStorageType::get(type_result._types[0], *ast)); |
| } else { |
| result._error = "couldn't resolve referent type"; |
| } |
| } |
| |
| static void |
| VisitNodeWeak(ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| VisitNodeResult type_result; |
| VisitNode(ast, cur_node->getFirstChild(), type_result); |
| if (type_result._types.size() == 1 && type_result._types[0]) { |
| result._types.push_back( |
| WeakStorageType::get(type_result._types[0], *ast)); |
| } else { |
| result._error = "couldn't resolve referent type"; |
| } |
| } |
| |
| static void |
| VisitNodeGenericParam(ASTContext *ast, |
| Demangle::NodePointer cur_node, |
| VisitNodeResult &result) { |
| if (cur_node->getNumChildren() == 2) { |
| auto first = cur_node->getChild(0); |
| auto second = cur_node->getChild(1); |
| if (first->getKind() == Demangle::Node::Kind::Index && |
| second->getKind() == Demangle::Node::Kind::Index) { |
| result._types.push_back( |
| GenericTypeParamType::get(first->getIndex(), |
| second->getIndex(), *ast)); |
| return; |
| } |
| } |
| |
| result._error = "bad generic param type"; |
| } |
| |
| static void VisitFirstChildNode( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| if (cur_node->begin() != cur_node->end()) { |
| VisitNode(ast, cur_node->getFirstChild(), result); |
| } |
| } |
| |
| static void VisitAllChildNodes( |
| ASTContext *ast, |
| Demangle::NodePointer cur_node, VisitNodeResult &result) { |
| Demangle::Node::iterator child_end = cur_node->end(); |
| for (Demangle::Node::iterator child_pos = cur_node->begin(); |
| child_pos != child_end; ++child_pos) { |
| VisitNode(ast, *child_pos, result); |
| } |
| } |
| |
| static void VisitNodeGlobal(ASTContext *ast, Demangle::NodePointer cur_node, |
| VisitNodeResult &result) { |
| assert(result._error.empty()); |
| |
| for (const auto &child : *cur_node) { |
| switch (child->getKind()) { |
| case Demangle::Node::Kind::Identifier: |
| result._error = "invalid global node"; |
| break; |
| default: |
| VisitNode(ast, child, result); |
| break; |
| } |
| } |
| } |
| |
| static void VisitNode( |
| ASTContext *ast, |
| Demangle::NodePointer node, VisitNodeResult &result) { |
| assert(result._error.empty()); |
| |
| const Demangle::Node::Kind nodeKind = node->getKind(); |
| |
| switch (nodeKind) { |
| case Demangle::Node::Kind::OwningAddressor: |
| case Demangle::Node::Kind::OwningMutableAddressor: |
| case Demangle::Node::Kind::UnsafeAddressor: |
| case Demangle::Node::Kind::UnsafeMutableAddressor: |
| VisitNodeAddressor(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::ArgumentTuple: |
| VisitFirstChildNode(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::AssociatedTypeRef: |
| VisitNodeAssociatedTypeRef(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::BoundGenericClass: |
| case Demangle::Node::Kind::BoundGenericStructure: |
| case Demangle::Node::Kind::BoundGenericEnum: |
| case Demangle::Node::Kind::BoundGenericOtherNominalType: |
| VisitNodeBoundGeneric(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::BuiltinTypeName: |
| VisitNodeBuiltinTypeName(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::Structure: |
| case Demangle::Node::Kind::Class: |
| case Demangle::Node::Kind::Enum: |
| case Demangle::Node::Kind::OtherNominalType: |
| case Demangle::Node::Kind::Protocol: |
| VisitNodeNominal(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::TypeAlias: |
| VisitNodeTypeAlias(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::Global: |
| VisitNodeGlobal(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::Static: |
| case Demangle::Node::Kind::Type: |
| case Demangle::Node::Kind::TypeMangling: |
| case Demangle::Node::Kind::ReturnType: |
| VisitAllChildNodes(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::Allocator: |
| case Demangle::Node::Kind::Constructor: |
| VisitNodeConstructor(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::Destructor: |
| VisitNodeDestructor(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::DeclContext: |
| VisitNodeDeclContext(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::ErrorType: |
| result._error = "error type encountered while demangling name"; |
| break; |
| |
| case Demangle::Node::Kind::Extension: |
| VisitNodeExtension(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::ExplicitClosure: |
| VisitNodeExplicitClosure(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::Function: |
| case Demangle::Node::Kind::Variable: |
| case Demangle::Node::Kind::Subscript: // Out of order on purpose |
| VisitNodeFunction(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::FunctionType: |
| case Demangle::Node::Kind::NoEscapeFunctionType: |
| case Demangle::Node::Kind::UncurriedFunctionType: // Out of order on |
| // purpose. |
| VisitNodeFunctionType(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::ImplFunctionType: |
| VisitNodeImplFunctionType(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::DidSet: |
| case Demangle::Node::Kind::Getter: |
| case Demangle::Node::Kind::Setter: |
| case Demangle::Node::Kind::WillSet: // out of order on purpose |
| VisitNodeSetterGetter(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::InOut: |
| VisitNodeInOut(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::ExistentialMetatype: |
| VisitNodeExistentialMetatype(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::Metatype: |
| VisitNodeMetatype(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::Module: |
| VisitNodeModule(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::Tuple: |
| VisitNodeTuple(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::ProtocolList: |
| VisitNodeProtocolList(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::ProtocolListWithClass: |
| VisitNodeProtocolListWithClass(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::ProtocolListWithAnyObject: |
| VisitNodeProtocolListWithAnyObject(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::QualifiedArchetype: |
| VisitNodeQualifiedArchetype(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::TupleElement: |
| VisitNodeTupleElement(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::TypeList: |
| VisitNodeTypeList(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::Unowned: |
| VisitNodeUnowned(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::Weak: |
| VisitNodeWeak(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::DependentGenericParamType: |
| VisitNodeGenericParam(ast, node, result); |
| break; |
| |
| case Demangle::Node::Kind::LocalDeclName: |
| case Demangle::Node::Kind::Identifier: |
| case Demangle::Node::Kind::PrivateDeclName: |
| llvm_unreachable("Must handle these as part of another node"); |
| |
| default: |
| break; |
| } |
| } |
| |
| Decl *ide::getDeclFromUSR(ASTContext &context, StringRef USR, |
| std::string &error) { |
| if (!USR.startswith("s:")) { |
| error = "not a Swift USR"; |
| return nullptr; |
| } |
| |
| std::string mangledName(USR); |
| // Convert to a symbol name by replacing the USR prefix. |
| // This relies on USR generation being very close to symbol mangling; if we |
| // need to support entities with customized USRs (e.g. extensions), we will |
| // need to do something smarter here. |
| mangledName.replace(0, 2, MANGLING_PREFIX_STR); |
| |
| return getDeclFromMangledSymbolName(context, mangledName, error); |
| } |
| |
| Decl *ide::getDeclFromMangledSymbolName(ASTContext &context, |
| StringRef mangledName, |
| std::string &error) { |
| Demangle::Context DemangleCtx; |
| auto node = DemangleCtx.demangleSymbolAsNode(mangledName); |
| VisitNodeResult result; |
| |
| if (node) |
| VisitNode(&context, node, result); |
| error = result._error; |
| if (error.empty() && result._decls.size() == 1) { |
| return result._decls.front(); |
| } else { |
| llvm::raw_string_ostream OS(error); |
| OS << "decl for symbol name '" << mangledName << "' was not found"; |
| return nullptr; |
| } |
| return nullptr; |
| } |
| |
| Type ide::getTypeFromMangledSymbolname(ASTContext &Ctx, |
| StringRef mangledName, |
| std::string &error) { |
| Demangle::Context DemangleCtx; |
| auto node = DemangleCtx.demangleSymbolAsNode(mangledName); |
| VisitNodeResult result; |
| |
| if (node) |
| VisitNode(&Ctx, node, result); |
| error = result._error; |
| if (error.empty() && result._types.size() == 1) { |
| return result._types.front().getPointer(); |
| } else { |
| error = stringWithFormat("type for symbolname '%s' was not found", |
| mangledName); |
| return Type(); |
| } |
| return Type(); |
| } |