[Swift] Type Scanner (2) - Swift Testing을 분석하여 Test 타입 찾기
Test+Discovery.swift#L26를 보면, __🟠$test_container__
문자열이 포함된 타입 이름을 찾을려는 것을 _testContainerTypeNameMagic
속성 이름을 통해 알 수 있습니다.
또한, 아래 all 속성에서 enumerateTypes(withNamesContaining:)
를 이용하여 __🟠$test_container__
문자열이 포함된 타입을 추출하여, 해당 타입이 __TestContainer.Type
타입인지 체크를 한 뒤, __tests
를 꺼내어 Sequence
에 넣어, 테스트를 수행할려는 것을 확인할 수 있습니다.
enumerateTypes(withNamesContaining:)
함수는 Test+Discovery.swift#L69에서 찾을 수 있습니다.
이 함수에서 실질적인 동작을 수행하는 함수인 swt_enumerateTypes(withNamesContaining:_:_:)
를 찾아야 합니다.
이 함수는 Discovery.h#L40에서 찾을 수 있습니다. swt_enumerateTypesWithNamesContaining
함수로, Swift에서 이름을 축약해서 사용할 수 있도록 SWT_SWIFT_NAME(swt_enumerateTypes(withNamesContaining:_:_:))
코드를 작성한 것을 확인할 수 있습니다.
이제 swt_enumerateTypesWithNamesContaining
함수가 구현된 Discovery.cpp를 확인해봅시다.
void swt_enumerateTypesWithNamesContaining(const char *nameSubstring, void *context, SWTTypeEnumerator body) {
enumerateTypeMetadataSections([=] (const SWTSectionBounds<SWTTypeMetadataRecord>& sectionBounds, bool *stop) {
for (const auto& record : sectionBounds) {
auto contextDescriptor = record.getContextDescriptor();
if (!contextDescriptor) {
// This type metadata record is invalid (or we don't understand how to
// get its context descriptor), so skip it.
continue;
} else if (contextDescriptor->isGeneric()) {
// Generic types cannot be fully instantiated without generic
// parameters, which is not something we can know abstractly.
continue;
}
// Check that the type's name passes. This will be more expensive than the
// checks above, but should be cheaper than realizing the metadata.
const char *typeName = contextDescriptor->getName();
bool nameOK = typeName && nullptr != std::strstr(typeName, nameSubstring);
if (!nameOK) {
continue;
}
if (void *typeMetadata = contextDescriptor->getMetadata()) {
body(sectionBounds.imageAddress, typeMetadata, stop, context);
}
}
});
}
enumerateTypeMetadataSections
함수를 통해 현재 프로세스에 로드된 Swift 타입 메타데이터 섹션을 열거하고, 각 섹션 내의 모든 타입 메타데이터 레코드를 반복 처리합니다.
메타데이터 레코드가 유효하지 않거나, 제네릭이면 건너뜁니다.
const char *typeName = contextDescriptor->getName();
에서 타입 이름을 가져와서, 해당 이름에 __🟠$test_container__
문자열이 포함되어 있는지 검사하고, 일치하면 타입 메타데이터를 가져와 이미지 주소, 타입 메타데이터, 중지 플래그, 컨텍스트 정보를 전달합니다.
즉, 타입 이름에 주어진 문자열이 포함되는 Swift 타입들을 찾아 넘겨주는 역할을 합니다. 이 방식은 enum, struct, class 등의 모든 타입을 찾아내기 위에 사용할 수 있습니다.
이를 이용하면, 타입 메타데이터를 스캔하는 기능을 만들어낼 수 있습니다.