mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
"Accessibility" has a different meaning for app developers, so we've already deliberately excised it from our diagnostics in favor of terms like "access control" and "access level". Do the same in the compiler now that we aren't constantly pulling things into the release branch. This commit changes the 'Accessibility' enum to be named 'AccessLevel'.
238 lines
7.7 KiB
C++
238 lines
7.7 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/ParameterList.h"
|
|
#include "swift/AST/Types.h"
|
|
|
|
using namespace swift;
|
|
using namespace swift::index;
|
|
|
|
static NominalTypeDecl *getNominalParent(const ValueDecl *D) {
|
|
Type Ty = D->getDeclContext()->getDeclaredTypeOfContext();
|
|
if (!Ty)
|
|
return nullptr;
|
|
return Ty->getAnyNominal();
|
|
}
|
|
|
|
/// \returns true if \c D is a subclass of 'XCTestCase'.
|
|
static bool isUnitTestCase(const ClassDecl *D) {
|
|
if (!D)
|
|
return false;
|
|
while (auto *SuperD = D->getSuperclassDecl()) {
|
|
if (SuperD->getNameStr() == "XCTestCase")
|
|
return true;
|
|
D = SuperD;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
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->getParameterLists().size() != 2)
|
|
return false;
|
|
if (FD->getParameterList(1)->size() != 0)
|
|
return false;
|
|
|
|
// 5. ...is of at least 'internal' accessibility (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 (FD->isAccessor()) {
|
|
sym.SubKind = getSubKindForAccessor(FD->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::getSymbolInfoForDecl(const Decl *D) {
|
|
SymbolInfo info{ SymbolKind::Unknown, SymbolSubKind::None,
|
|
SymbolPropertySet(), SymbolLanguage::Swift };
|
|
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);
|
|
if (!ED->getExtendedType())
|
|
break;
|
|
NominalTypeDecl *NTD = ED->getExtendedType()->getAnyNominal();
|
|
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::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;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (isLocalSymbol(D)) {
|
|
info.Properties |= SymbolProperty::Local;
|
|
}
|
|
|
|
return info;
|
|
}
|
|
|
|
SymbolSubKind index::getSubKindForAccessor(AccessorKind AK) {
|
|
switch (AK) {
|
|
case AccessorKind::NotAccessor: return SymbolSubKind::None;
|
|
case AccessorKind::IsGetter: return SymbolSubKind::AccessorGetter;
|
|
case AccessorKind::IsSetter: return SymbolSubKind::AccessorSetter;
|
|
case AccessorKind::IsWillSet: return SymbolSubKind::SwiftAccessorWillSet;
|
|
case AccessorKind::IsDidSet: return SymbolSubKind::SwiftAccessorDidSet;
|
|
case AccessorKind::IsAddressor: return SymbolSubKind::SwiftAccessorAddressor;
|
|
case AccessorKind::IsMutableAddressor:
|
|
return SymbolSubKind::SwiftAccessorMutableAddressor;
|
|
case AccessorKind::IsMaterializeForSet:
|
|
llvm_unreachable("unexpected MaterializeForSet");
|
|
}
|
|
|
|
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);
|
|
}
|