mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Clang importer] Basic import-as-member inference system
Introduces import-as-member (IAM) inferene system, to automatically infer details that would otherwise have to be manually specified with the swift_name attribute. Basic functionality present, though there are some issues with properties at the moment. No hooks, options, or tests yet, stay tuned.
This commit is contained in:
@@ -182,6 +182,16 @@ namespace swift {
|
|||||||
unsigned getPosition() const {
|
unsigned getPosition() const {
|
||||||
return Position;
|
return Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve the string up until this iterator
|
||||||
|
StringRef getPriorStr() const {
|
||||||
|
return String.slice(0, Position);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the rest of the string (including this position)
|
||||||
|
StringRef getRestOfStr() const {
|
||||||
|
return String.slice(Position, String.size());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Find the first camelCase word in the given string.
|
/// Find the first camelCase word in the given string.
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ handle_gyb_sources(
|
|||||||
add_swift_library(swiftClangImporter
|
add_swift_library(swiftClangImporter
|
||||||
ClangDiagnosticConsumer.cpp
|
ClangDiagnosticConsumer.cpp
|
||||||
ClangImporter.cpp
|
ClangImporter.cpp
|
||||||
|
IAMInference.cpp
|
||||||
ImportDecl.cpp
|
ImportDecl.cpp
|
||||||
ImportEnumInfo.cpp
|
ImportEnumInfo.cpp
|
||||||
ImportMacro.cpp
|
ImportMacro.cpp
|
||||||
|
|||||||
440
lib/ClangImporter/IAMInference.cpp
Normal file
440
lib/ClangImporter/IAMInference.cpp
Normal file
@@ -0,0 +1,440 @@
|
|||||||
|
//===--- IAMInference.cpp - Import as member inference system -------------===//
|
||||||
|
//
|
||||||
|
// This source file is part of the Swift.org open source project
|
||||||
|
//
|
||||||
|
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||||
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||||
|
//
|
||||||
|
// See http://swift.org/LICENSE.txt for license information
|
||||||
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// This file implements support for inferring when globals can be imported as
|
||||||
|
// members
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
#include "IAMInference.h"
|
||||||
|
|
||||||
|
#include "clang/AST/ASTContext.h"
|
||||||
|
#include "clang/AST/Decl.h"
|
||||||
|
#include "clang/Sema/Sema.h"
|
||||||
|
#include "clang/Sema/Lookup.h"
|
||||||
|
|
||||||
|
#include "swift/AST/ASTContext.h"
|
||||||
|
#include "swift/Basic/StringExtras.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
using namespace swift;
|
||||||
|
|
||||||
|
using NameBuffer = SmallString<32>;
|
||||||
|
|
||||||
|
static const std::array<StringRef, 2> InitSpecifiers{{
|
||||||
|
StringRef("Create"), StringRef("Make"),
|
||||||
|
}};
|
||||||
|
static const std::array<StringRef, 2> PropertySpecifiers{{
|
||||||
|
StringRef("Get"), StringRef("Set"),
|
||||||
|
}};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
enum class CFNameKind : unsigned {
|
||||||
|
None,
|
||||||
|
CFType,
|
||||||
|
NonCFType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
static CFNameKind getCFNameKind(StringRef name) {
|
||||||
|
#define CF_TYPE(TYPE) \
|
||||||
|
if (name == #TYPE) \
|
||||||
|
return CFNameKind::CFType;
|
||||||
|
#define NON_CF_TYPE(TYPE) \
|
||||||
|
if (name == #TYPE) \
|
||||||
|
return CFNameKind::NonCFType;
|
||||||
|
#include "CFDatabase.def"
|
||||||
|
return CFNameKind::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isCFTypeName(StringRef name) {
|
||||||
|
return getCFNameKind(name) == CFNameKind::CFType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static bool isExplicitNonCFTypeName(StringRef name) {
|
||||||
|
// return getCFNameKind(name) == CFNameKind::NonCFType;
|
||||||
|
// }
|
||||||
|
|
||||||
|
IAMOptions IAMOptions::getDefault() { return {}; }
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class IAMInference {
|
||||||
|
ASTContext &context;
|
||||||
|
clang::Sema &clangSema;
|
||||||
|
IAMOptions options;
|
||||||
|
|
||||||
|
public:
|
||||||
|
IAMInference(ASTContext &ctx, clang::Sema &sema, IAMOptions opts)
|
||||||
|
: context(ctx), clangSema(sema), options(opts) {
|
||||||
|
(void)options;
|
||||||
|
}
|
||||||
|
|
||||||
|
IAMResult infer(const clang::NamedDecl *);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// typeID
|
||||||
|
IAMResult importAsTypeID(const clang::QualType typeIDTy,
|
||||||
|
EffectiveClangContext effectiveDC) {
|
||||||
|
return {context.getIdentifier("typeID"), IAMAccessorKind::Getter,
|
||||||
|
effectiveDC};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init
|
||||||
|
IAMResult importAsConstructor(StringRef name, StringRef initSpecifier,
|
||||||
|
ArrayRef<const clang::ParmVarDecl *> params,
|
||||||
|
EffectiveClangContext effectiveDC) {
|
||||||
|
if (name != "init") {
|
||||||
|
// TODO: move words onto argument labels, as dictated by options
|
||||||
|
}
|
||||||
|
return {formDeclName("init", params, ""), effectiveDC};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instance computed property
|
||||||
|
IAMResult
|
||||||
|
importAsInstanceProperty(StringRef name, StringRef propSpec, unsigned selfIdx,
|
||||||
|
ArrayRef<const clang::ParmVarDecl *> nonSelfParams,
|
||||||
|
const clang::FunctionDecl *pairedAccessor,
|
||||||
|
EffectiveClangContext effectiveDC) {
|
||||||
|
IAMAccessorKind kind =
|
||||||
|
propSpec == "Get" ? IAMAccessorKind::Getter : IAMAccessorKind::Setter;
|
||||||
|
assert(kind == IAMAccessorKind::Getter || pairedAccessor && "no set-only");
|
||||||
|
|
||||||
|
return {formDeclName(name, nonSelfParams), kind, selfIdx, effectiveDC};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instance method
|
||||||
|
IAMResult
|
||||||
|
importAsInstanceMethod(StringRef name, unsigned selfIdx,
|
||||||
|
ArrayRef<const clang::ParmVarDecl *> nonSelfParams,
|
||||||
|
EffectiveClangContext effectiveDC) {
|
||||||
|
return {formDeclName(name, nonSelfParams), selfIdx, effectiveDC};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static stored property
|
||||||
|
IAMResult importAsStaticProperty(StringRef name,
|
||||||
|
EffectiveClangContext effectiveDC) {
|
||||||
|
return {context.getIdentifier(name), effectiveDC};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static computed property
|
||||||
|
IAMResult
|
||||||
|
importAsStaticProperty(StringRef name, StringRef propSpec,
|
||||||
|
ArrayRef<const clang::ParmVarDecl *> nonSelfParams,
|
||||||
|
const clang::FunctionDecl *pairedAccessor,
|
||||||
|
EffectiveClangContext effectiveDC) {
|
||||||
|
IAMAccessorKind kind =
|
||||||
|
propSpec == "Get" ? IAMAccessorKind::Getter : IAMAccessorKind::Setter;
|
||||||
|
assert(kind == IAMAccessorKind::Getter || pairedAccessor && "no set-only");
|
||||||
|
|
||||||
|
return {formDeclName(name, nonSelfParams), kind, effectiveDC};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static method
|
||||||
|
IAMResult
|
||||||
|
importAsStaticMethod(StringRef name,
|
||||||
|
ArrayRef<const clang::ParmVarDecl *> nonSelfParams,
|
||||||
|
EffectiveClangContext effectiveDC) {
|
||||||
|
return {formDeclName(name, nonSelfParams), effectiveDC};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename DeclType>
|
||||||
|
inline DeclType *clangLookup(StringRef name,
|
||||||
|
clang::Sema::LookupNameKind kind);
|
||||||
|
|
||||||
|
clang::TypedefNameDecl *clangLookupTypedef(StringRef name) {
|
||||||
|
return clangLookup<clang::TypedefNameDecl>(
|
||||||
|
name, clang::Sema::LookupNameKind::LookupOrdinaryName);
|
||||||
|
}
|
||||||
|
clang::FunctionDecl *clangLookupFunction(StringRef name) {
|
||||||
|
return clangLookup<clang::FunctionDecl>(
|
||||||
|
name, clang::Sema::LookupNameKind::LookupOrdinaryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
const clang::TypedefNameDecl *findTypeAndMatch(StringRef workingName,
|
||||||
|
NameBuffer &outStr) {
|
||||||
|
// FIXME: drop mutable...
|
||||||
|
|
||||||
|
// Longest-prefix matching, alternate with checking for a trailing "Ref"
|
||||||
|
// suffix and the prefix itself. We iterate from the back to the beginning.
|
||||||
|
auto words = camel_case::getWords(workingName);
|
||||||
|
for (auto rWordsIter = words.rbegin(), rWordsEnd = words.rend();
|
||||||
|
rWordsIter != rWordsEnd; ++rWordsIter) {
|
||||||
|
NameBuffer nameAttempt;
|
||||||
|
nameAttempt.append(rWordsIter.base().getPriorStr());
|
||||||
|
nameAttempt.append(*rWordsIter);
|
||||||
|
StringRef prefix = nameAttempt;
|
||||||
|
nameAttempt.append("Ref");
|
||||||
|
StringRef prefixWithRef = nameAttempt;
|
||||||
|
|
||||||
|
if (auto tyDecl = clangLookupTypedef(prefixWithRef)) {
|
||||||
|
outStr.append(workingName.drop_front(prefix.size()));
|
||||||
|
return tyDecl;
|
||||||
|
}
|
||||||
|
if (auto tyDecl = clangLookupTypedef(prefix)) {
|
||||||
|
outStr.append(workingName.drop_front(prefix.size()));
|
||||||
|
return tyDecl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const clang::FunctionDecl *findPairedAccessor(StringRef name,
|
||||||
|
StringRef propSpec) {
|
||||||
|
NameBuffer pairName;
|
||||||
|
auto words = camel_case::getWords(name);
|
||||||
|
for (auto word : words) {
|
||||||
|
if (word == propSpec) {
|
||||||
|
if (propSpec == "Get") {
|
||||||
|
pairName.append("Set");
|
||||||
|
} else {
|
||||||
|
assert(propSpec == "Set");
|
||||||
|
pairName.append("Get");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pairName.append(word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return clangLookupFunction(pairName);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeclName formDeclName(StringRef baseName,
|
||||||
|
ArrayRef<const clang::ParmVarDecl *> params,
|
||||||
|
StringRef firstPrefix = "") {
|
||||||
|
SmallVector<Identifier, 8> argLabels;
|
||||||
|
for (unsigned i = 0; i < params.size(); ++i) {
|
||||||
|
if (firstPrefix != "") {
|
||||||
|
// TODO: move words onto argument labels
|
||||||
|
}
|
||||||
|
argLabels.push_back(context.getIdentifier(params[i]->getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {context, context.getIdentifier(baseName), argLabels};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool match(StringRef str, StringRef toMatch, NameBuffer &outStr) {
|
||||||
|
// TODO: let options dictate fuzzy matching...
|
||||||
|
|
||||||
|
// FIXME: drop mutable...
|
||||||
|
|
||||||
|
auto strWords = camel_case::getWords(str);
|
||||||
|
auto matchWords = camel_case::getWords(toMatch);
|
||||||
|
|
||||||
|
auto strIter = strWords.begin();
|
||||||
|
auto matchIter = matchWords.begin();
|
||||||
|
|
||||||
|
// Match in order, but allowing interjected words
|
||||||
|
while (strIter != strWords.end()) {
|
||||||
|
if (matchIter == matchWords.end()) {
|
||||||
|
// We matched them all!
|
||||||
|
outStr.append(strIter.getRestOfStr());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (*strIter == *matchIter) {
|
||||||
|
// It's a match!
|
||||||
|
++strIter;
|
||||||
|
++matchIter;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Move on to the next one
|
||||||
|
outStr.append(*strIter);
|
||||||
|
++strIter;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isStructType(clang::QualType qt) {
|
||||||
|
if (qt->isPointerType())
|
||||||
|
qt = qt->getPointeeType();
|
||||||
|
return qt->getUnqualifiedDesugaredType()->isStructureType();
|
||||||
|
}
|
||||||
|
|
||||||
|
static StringRef getStructTypeName(clang::QualType qt) {
|
||||||
|
// We only reason about imported struct types
|
||||||
|
if (!isStructType(qt))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (auto typedefTy = qt->getAs<clang::TypedefType>()) {
|
||||||
|
// Use the sugar-ed, but un-ref-ed name
|
||||||
|
auto name = typedefTy->getDecl()->getName();
|
||||||
|
if (name.endswith("Ref") && isCFTypeName(name))
|
||||||
|
return name.drop_back(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto identInfo = qt.getBaseTypeIdentifier();
|
||||||
|
if (identInfo)
|
||||||
|
return identInfo->getName();
|
||||||
|
|
||||||
|
// Otherwise, no name
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the canonical, but still sugar-ed, effective decl context
|
||||||
|
static EffectiveClangContext getEffectiveDC(clang::QualType qt) {
|
||||||
|
auto ty = qt.getTypePtr();
|
||||||
|
if (auto typedefType = ty->getAs<clang::TypedefType>())
|
||||||
|
return {typedefType->getDecl()->getCanonicalDecl()};
|
||||||
|
|
||||||
|
auto pointeeQT = ty->getPointeeType();
|
||||||
|
if (pointeeQT != clang::QualType())
|
||||||
|
ty = pointeeQT.getTypePtr();
|
||||||
|
|
||||||
|
if (auto typedefType = ty->getAs<clang::TypedefType>()) {
|
||||||
|
return {typedefType->getDecl()->getCanonicalDecl()};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const clang::RecordType *recTy = ty->getAsStructureType())
|
||||||
|
return {recTy->getDecl()->getCanonicalDecl()};
|
||||||
|
|
||||||
|
assert(0 && "not a valid Clang context");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static EffectiveClangContext getEffectiveDC(const clang::TypeDecl *tyDecl) {
|
||||||
|
// FIXME: ewwe
|
||||||
|
auto typeDecl = const_cast<clang::TypeDecl *>(tyDecl);
|
||||||
|
if (auto typedefName = dyn_cast<clang::TypedefNameDecl>(typeDecl))
|
||||||
|
return {typedefName->getCanonicalDecl()};
|
||||||
|
if (auto rDecl = dyn_cast<clang::RecordDecl>(typeDecl))
|
||||||
|
return {rDecl->getCanonicalDecl()};
|
||||||
|
|
||||||
|
assert("expected valid Clang context");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool hasWord(StringRef s, StringRef matchWord) {
|
||||||
|
for (auto word : camel_case::getWords(s))
|
||||||
|
if (word == matchWord)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
IAMResult IAMInference::infer(const clang::NamedDecl *clangDecl) {
|
||||||
|
if (auto varDecl = dyn_cast<clang::VarDecl>(clangDecl)) {
|
||||||
|
// Try to find a type to add this as a static property to
|
||||||
|
StringRef workingName = varDecl->getName();
|
||||||
|
NameBuffer remainingName;
|
||||||
|
const clang::TypeDecl *tyDecl =
|
||||||
|
findTypeAndMatch(workingName, remainingName);
|
||||||
|
if (tyDecl)
|
||||||
|
return importAsStaticProperty(remainingName, getEffectiveDC(tyDecl));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to infer a member function
|
||||||
|
auto funcDecl = dyn_cast<clang::FunctionDecl>(clangDecl);
|
||||||
|
if (!funcDecl)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// FIXME: drop "Mutable"...
|
||||||
|
|
||||||
|
StringRef workingName = funcDecl->getName();
|
||||||
|
auto retTy = funcDecl->getReturnType();
|
||||||
|
unsigned numParams = funcDecl->getNumParams();
|
||||||
|
|
||||||
|
// 0) Special cases are specially handled: *GetTypeID()
|
||||||
|
//
|
||||||
|
StringRef getTypeID = "GetTypeID";
|
||||||
|
if (numParams == 0 && workingName.endswith(getTypeID))
|
||||||
|
if (auto tyDecl =
|
||||||
|
clangLookupTypedef(workingName.drop_back(getTypeID.size())))
|
||||||
|
return importAsTypeID(retTy, tyDecl);
|
||||||
|
|
||||||
|
// 1) If we find an init specifier and our name matches the return type, we
|
||||||
|
// import as some kind of constructor
|
||||||
|
//
|
||||||
|
if (!retTy->isVoidType()) {
|
||||||
|
NameBuffer remainingName;
|
||||||
|
StringRef typeName = getStructTypeName(retTy);
|
||||||
|
if (typeName != StringRef())
|
||||||
|
if (match(workingName, typeName, remainingName))
|
||||||
|
for (auto initSpec : InitSpecifiers)
|
||||||
|
if (hasWord(remainingName, initSpec))
|
||||||
|
return importAsConstructor(
|
||||||
|
remainingName, initSpec,
|
||||||
|
{funcDecl->param_begin(), funcDecl->param_end()},
|
||||||
|
getEffectiveDC(retTy));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) If we find a likely self reference in the parameters, make an instance
|
||||||
|
// member (method or property)
|
||||||
|
//
|
||||||
|
SmallVector<const clang::ParmVarDecl *, 8> nonSelfParams;
|
||||||
|
unsigned selfIdx = 0;
|
||||||
|
for (auto paramI = funcDecl->param_begin(), paramE = funcDecl->param_end();
|
||||||
|
paramI != paramE; ++paramI, ++selfIdx) {
|
||||||
|
auto param = *paramI;
|
||||||
|
NameBuffer remainingName;
|
||||||
|
StringRef typeName = getStructTypeName(param->getType());
|
||||||
|
if (typeName != StringRef()) {
|
||||||
|
if (match(workingName, typeName, remainingName)) {
|
||||||
|
auto effectiveDC = getEffectiveDC(param->getType());
|
||||||
|
nonSelfParams.append(funcDecl->param_begin(), paramI);
|
||||||
|
nonSelfParams.append(++paramI, paramE);
|
||||||
|
// See if it's a property
|
||||||
|
for (auto propSpec : PropertySpecifiers) {
|
||||||
|
NameBuffer propName;
|
||||||
|
if (match(remainingName, propSpec, propName))
|
||||||
|
if (auto pair = findPairedAccessor(workingName, propSpec))
|
||||||
|
return importAsInstanceProperty(propName, propSpec, selfIdx,
|
||||||
|
nonSelfParams, pair, effectiveDC);
|
||||||
|
}
|
||||||
|
|
||||||
|
return importAsInstanceMethod(remainingName, selfIdx, nonSelfParams,
|
||||||
|
effectiveDC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) Finally, try to find a class to put this on as a static function
|
||||||
|
NameBuffer remainingName;
|
||||||
|
if (const clang::TypeDecl *tyDecl =
|
||||||
|
findTypeAndMatch(workingName, remainingName)) {
|
||||||
|
auto effectiveDC = getEffectiveDC(tyDecl);
|
||||||
|
|
||||||
|
ArrayRef<const clang::ParmVarDecl *> params = {funcDecl->param_begin(),
|
||||||
|
funcDecl->param_end()};
|
||||||
|
// See if it's a property
|
||||||
|
for (auto propSpec : PropertySpecifiers) {
|
||||||
|
NameBuffer propName;
|
||||||
|
if (match(remainingName, propSpec, propName))
|
||||||
|
if (auto pair = findPairedAccessor(workingName, propSpec))
|
||||||
|
return importAsStaticProperty(propName, propSpec, nonSelfParams, pair,
|
||||||
|
effectiveDC);
|
||||||
|
}
|
||||||
|
|
||||||
|
return importAsStaticMethod(remainingName, nonSelfParams, effectiveDC);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename DeclType>
|
||||||
|
DeclType *IAMInference::clangLookup(StringRef name,
|
||||||
|
clang::Sema::LookupNameKind kind) {
|
||||||
|
clang::IdentifierInfo *nameII = &clangSema.getASTContext().Idents.get(name);
|
||||||
|
clang::LookupResult lookupResult(clangSema, clang::DeclarationName(nameII),
|
||||||
|
clang::SourceLocation(), kind);
|
||||||
|
if (!clangSema.LookupName(lookupResult, clangSema.TUScope))
|
||||||
|
return nullptr;
|
||||||
|
return lookupResult.getAsSingle<DeclType>()->getCanonicalDecl();
|
||||||
|
}
|
||||||
|
|
||||||
|
IAMResult IAMResult::infer(ASTContext &ctx, clang::Sema &clangSema,
|
||||||
|
const clang::NamedDecl *decl, IAMOptions opts) {
|
||||||
|
IAMInference inference(ctx, clangSema, opts);
|
||||||
|
return inference.infer(decl);
|
||||||
|
}
|
||||||
103
lib/ClangImporter/IAMInference.h
Normal file
103
lib/ClangImporter/IAMInference.h
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
//===--- IAMInference.h - Import as member inference system ---------------===//
|
||||||
|
//
|
||||||
|
// This source file is part of the Swift.org open source project
|
||||||
|
//
|
||||||
|
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||||
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||||
|
//
|
||||||
|
// See http://swift.org/LICENSE.txt for license information
|
||||||
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// This file implements support for inferring when globals can be imported as
|
||||||
|
// members
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef SWIFT_IMPORTER_IMPORT_AS_MEMBER_INFERENCE_H
|
||||||
|
#define SWIFT_IMPORTER_IMPORT_AS_MEMBER_INFERENCE_H
|
||||||
|
|
||||||
|
#include "SwiftLookupTable.h"
|
||||||
|
|
||||||
|
#include "llvm/ADT/Optional.h"
|
||||||
|
#include "llvm/ADT/StringRef.h"
|
||||||
|
|
||||||
|
#include "swift/AST/Identifier.h"
|
||||||
|
|
||||||
|
namespace clang {
|
||||||
|
class Sema;
|
||||||
|
class NamedDecl;
|
||||||
|
class TypeDecl;
|
||||||
|
class FunctionDecl;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace swift {
|
||||||
|
|
||||||
|
// Import As Member -- attempt to import C global functions and variables as
|
||||||
|
// members on types or instances.
|
||||||
|
|
||||||
|
struct IAMOptions {
|
||||||
|
// TODO: fine-grained control over how we infer
|
||||||
|
static IAMOptions getDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class IAMAccessorKind : uint8_t { None, Getter, Setter };
|
||||||
|
|
||||||
|
/// The result of out inference system
|
||||||
|
struct IAMResult {
|
||||||
|
// The name to import as
|
||||||
|
DeclName name = {};
|
||||||
|
|
||||||
|
// If this is a getter/setter, the other accessor
|
||||||
|
const clang::FunctionDecl *pairedAccessor = nullptr;
|
||||||
|
|
||||||
|
IAMAccessorKind accessorKind = IAMAccessorKind::None;
|
||||||
|
|
||||||
|
Optional<unsigned> selfIndex = None;
|
||||||
|
|
||||||
|
// The canonical type decl we will import as a member of
|
||||||
|
EffectiveClangContext effectiveDC = {};
|
||||||
|
|
||||||
|
static IAMResult infer(ASTContext &, clang::Sema &, const clang::NamedDecl *,
|
||||||
|
IAMOptions = IAMOptions::getDefault());
|
||||||
|
|
||||||
|
IAMResult() = default;
|
||||||
|
|
||||||
|
// Static members
|
||||||
|
IAMResult(DeclName declName, EffectiveClangContext dc)
|
||||||
|
: name(declName), effectiveDC(dc) {}
|
||||||
|
|
||||||
|
IAMResult(DeclName declName, IAMAccessorKind kind, EffectiveClangContext dc)
|
||||||
|
: name(declName), accessorKind(kind), effectiveDC(dc) {}
|
||||||
|
|
||||||
|
// Instance members
|
||||||
|
IAMResult(DeclName declName, unsigned selfIdx, EffectiveClangContext dc)
|
||||||
|
: name(declName), selfIndex(selfIdx), effectiveDC(dc) {}
|
||||||
|
|
||||||
|
IAMResult(DeclName declName, IAMAccessorKind kind, unsigned selfIdx,
|
||||||
|
EffectiveClangContext dc)
|
||||||
|
: name(declName), accessorKind(kind), selfIndex(selfIdx),
|
||||||
|
effectiveDC(dc) {}
|
||||||
|
|
||||||
|
bool isImportAsMember() const { return bool(effectiveDC); }
|
||||||
|
|
||||||
|
bool isInstanceMember() const {
|
||||||
|
return isImportAsMember() && selfIndex.hasValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isStaticMember() const {
|
||||||
|
return isImportAsMember() && !selfIndex.hasValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isPropertyAccessor() const {
|
||||||
|
return accessorKind != IAMAccessorKind::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isInit() const {
|
||||||
|
return isStaticMember() && name.getBaseName().str() == "init";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SWIFT_IMPORTER_IMPORT_AS_MEMBER_INFERENCE_H
|
||||||
Reference in New Issue
Block a user