Files
swift-mirror/lib/Index/IndexSymbol.cpp
Joe Groff 71912bbfd6 AST: Represent OpaqueTypeDecls.
To represent the abstracted interface of an opaque type, we need a generic signature that refines
the outer context generic signature with an additional generic parameter representing the underlying
type and its exposed constraints. Opaque types also need to be keyed by their originating decl, so
that we can treat values of the same opaque type as the same. When we check a FuncDecl with an
opaque type specified as its return type, create an OpaqueTypeDecl and associate it with the
originating decl. (A representation for *types* derived from the opaque decl will come next.)
2019-04-17 14:43:32 -07:00

275 lines
8.8 KiB
C++

//===--- IndexSymbol.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/Index/IndexSymbol.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Module.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/Types.h"
using namespace swift;
using namespace swift::index;
static NominalTypeDecl *getNominalParent(const ValueDecl *D) {
return D->getDeclContext()->getSelfNominalTypeDecl();
}
/// \returns true if \c D is a subclass of 'XCTestCase'.
static bool isUnitTestCase(const ClassDecl *D) {
if (!D)
return false;
return D->walkSuperclasses([D](ClassDecl *SuperD) {
if (SuperD != D && // Do not treate XCTestCase itself as a test.
SuperD->getNameStr() == "XCTestCase")
return TypeWalker::Action::Stop; // Found test; stop and return true.
return TypeWalker::Action::Continue;
});
}
static bool isUnitTest(const ValueDecl *D) {
if (!D->hasName())
return false;
// A 'test candidate' is:
// 1. An instance method...
auto FD = dyn_cast<FuncDecl>(D);
if (!FD)
return false;
if (!D->isInstanceMember())
return false;
// 2. ...on a class or extension (not a struct) subclass of XCTestCase...
auto parentNTD = getNominalParent(D);
if (!parentNTD)
return false;
if (!isa<ClassDecl>(parentNTD))
return false;
if (!isUnitTestCase(cast<ClassDecl>(parentNTD)))
return false;
// 3. ...that returns void...
Type RetTy = FD->getResultInterfaceType();
if (RetTy && !RetTy->isVoid())
return false;
// 4. ...takes no parameters...
if (FD->getParameters()->size() != 0)
return false;
// 5. ...is of at least 'internal' access (unless we can use
// Objective-C reflection)...
if (!D->getASTContext().LangOpts.EnableObjCInterop &&
(D->getFormalAccess() < AccessLevel::Internal ||
parentNTD->getFormalAccess() < AccessLevel::Internal))
return false;
// 6. ...and starts with "test".
if (FD->getName().str().startswith("test"))
return true;
return false;
}
static void setFuncSymbolInfo(const FuncDecl *FD, SymbolInfo &sym) {
sym.Kind = SymbolKind::Function;
if (FD->getAttrs().hasAttribute<IBActionAttr>())
sym.Properties |= SymbolProperty::IBAnnotated;
if (isUnitTest(FD))
sym.Properties |= SymbolProperty::UnitTest;
if (FD->getDeclContext()->isTypeContext()) {
if (FD->isStatic()) {
if (FD->getCorrectStaticSpelling() == StaticSpellingKind::KeywordClass)
sym.Kind = SymbolKind::ClassMethod;
else
sym.Kind = SymbolKind::StaticMethod;
} else {
sym.Kind = SymbolKind::InstanceMethod;
}
}
if (auto accessor = dyn_cast<AccessorDecl>(FD)) {
sym.SubKind = getSubKindForAccessor(accessor->getAccessorKind());
return;
}
if (auto *op = FD->getOperatorDecl()) {
switch (op->getKind()) {
case DeclKind::PrefixOperator:
sym.SubKind = SymbolSubKind::SwiftPrefixOperator;
return;
case DeclKind::PostfixOperator:
sym.SubKind = SymbolSubKind::SwiftPostfixOperator;
return;
case DeclKind::InfixOperator:
sym.SubKind = SymbolSubKind::SwiftInfixOperator;
return;
default:
llvm_unreachable("unexpected operator kind");
}
}
}
static SymbolKind getVarSymbolKind(const VarDecl *VD) {
auto *DC = VD->getDeclContext();
if (DC->isTypeContext()) {
if (VD->isStatic()) {
if (VD->getCorrectStaticSpelling() == StaticSpellingKind::KeywordClass)
return SymbolKind::ClassProperty;
return SymbolKind::StaticProperty;
}
return SymbolKind::InstanceProperty;
}
return SymbolKind::Variable;
}
SymbolInfo index::getSymbolInfoForModule(ModuleEntity Mod) {
SymbolInfo info;
info.Kind = SymbolKind::Module;
info.SubKind = SymbolSubKind::None;
info.Properties = SymbolPropertySet();
if (auto *D = Mod.getAsSwiftModule()) {
if (!D->isClangModule()) {
info.Lang = SymbolLanguage::Swift;
} else {
info.Lang = SymbolLanguage::C;
}
} else if (Mod.getAsClangModule()) {
info.Lang = SymbolLanguage::C;
} else {
llvm_unreachable("unexpected module kind");
}
return info;
}
SymbolInfo index::getSymbolInfoForDecl(const Decl *D) {
SymbolInfo info{ SymbolKind::Unknown, SymbolSubKind::None,
SymbolLanguage::Swift, SymbolPropertySet() };
switch (D->getKind()) {
case DeclKind::Enum:
info.Kind = SymbolKind::Enum;
break;
case DeclKind::Struct:
info.Kind = SymbolKind::Struct;
break;
case DeclKind::Protocol:
info.Kind = SymbolKind::Protocol;
break;
case DeclKind::Class:
info.Kind = SymbolKind::Class;
if (isUnitTestCase(cast<ClassDecl>(D)))
info.Properties |= SymbolProperty::UnitTest;
break;
case DeclKind::Extension: {
info.Kind = SymbolKind::Extension;
auto *ED = cast<ExtensionDecl>(D);
NominalTypeDecl *NTD = ED->getExtendedNominal();
if (!NTD)
break;
if (isa<StructDecl>(NTD))
info.SubKind = SymbolSubKind::SwiftExtensionOfStruct;
else if (auto *CD = dyn_cast<ClassDecl>(NTD)) {
info.SubKind = SymbolSubKind::SwiftExtensionOfClass;
if (isUnitTestCase(CD))
info.Properties |= SymbolProperty::UnitTest;
} else if (isa<EnumDecl>(NTD))
info.SubKind = SymbolSubKind::SwiftExtensionOfEnum;
else if (isa<ProtocolDecl>(NTD))
info.SubKind = SymbolSubKind::SwiftExtensionOfProtocol;
assert(info.SubKind != SymbolSubKind::None);
break;
}
case DeclKind::TypeAlias: info.Kind = SymbolKind::TypeAlias; break;
case DeclKind::AssociatedType:
info.Kind = SymbolKind::TypeAlias;
info.SubKind = SymbolSubKind::SwiftAssociatedType;
break;
case DeclKind::GenericTypeParam:
info.Kind = SymbolKind::TypeAlias;
info.SubKind = SymbolSubKind::SwiftGenericTypeParam;
break;
case DeclKind::EnumElement: info.Kind = SymbolKind::EnumConstant; break;
case DeclKind::Subscript:
info.Kind = SymbolKind::InstanceProperty;
info.SubKind = SymbolSubKind::SwiftSubscript;
break;
case DeclKind::Constructor: info.Kind = SymbolKind::Constructor; break;
case DeclKind::Destructor: info.Kind = SymbolKind::Destructor; break;
case DeclKind::Param:
info.Kind = SymbolKind::Parameter;
break;
case DeclKind::Accessor:
case DeclKind::Func:
setFuncSymbolInfo(cast<FuncDecl>(D), info);
break;
case DeclKind::Var:
info.Kind = getVarSymbolKind(cast<VarDecl>(D));
if (D->getAttrs().hasAttribute<IBOutletAttr>())
info.Properties |= SymbolProperty::IBAnnotated;
if (D->getAttrs().hasAttribute<GKInspectableAttr>())
info.Properties |= SymbolProperty::GKInspectable;
break;
// Arguably these should be indexed?
case DeclKind::PrecedenceGroup:
case DeclKind::InfixOperator:
case DeclKind::PrefixOperator:
case DeclKind::PostfixOperator:
break;
// These all reflect some sort of uninteresting syntactic structure
// and don't merit indexing.
case DeclKind::Import:
case DeclKind::PatternBinding:
case DeclKind::EnumCase:
case DeclKind::TopLevelCode:
case DeclKind::IfConfig:
case DeclKind::PoundDiagnostic:
case DeclKind::MissingMember:
case DeclKind::Module:
case DeclKind::OpaqueType:
break;
}
if (isLocalSymbol(D)) {
info.Properties |= SymbolProperty::Local;
}
return info;
}
SymbolSubKind index::getSubKindForAccessor(AccessorKind AK) {
switch (AK) {
case AccessorKind::Get: return SymbolSubKind::AccessorGetter;
case AccessorKind::Set: return SymbolSubKind::AccessorSetter;
case AccessorKind::WillSet: return SymbolSubKind::SwiftAccessorWillSet;
case AccessorKind::DidSet: return SymbolSubKind::SwiftAccessorDidSet;
case AccessorKind::Address: return SymbolSubKind::SwiftAccessorAddressor;
case AccessorKind::MutableAddress:
return SymbolSubKind::SwiftAccessorMutableAddressor;
case AccessorKind::Read: return SymbolSubKind::SwiftAccessorRead;
case AccessorKind::Modify: return SymbolSubKind::SwiftAccessorModify;
}
llvm_unreachable("Unhandled AccessorKind in switch.");
}
bool index::isLocalSymbol(const swift::Decl *D) {
return D->getDeclContext()->getLocalContext() &&
(!isa<ParamDecl>(D) || cast<ParamDecl>(D)->getArgumentNameLoc().isValid() ||
D->getDeclContext()->getContextKind() == DeclContextKind::AbstractClosureExpr);
}