# REQUIRES: aarch64
# UNSUPPORTED: system-windows
#   due to awk usage

# RUN: rm -rf %t; split-file %s %t && cd %t

############ Test merging multiple categories into a single category ############
## Create a dylib with a fake base class to link against in when merging between categories
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-macos -o a64_fakedylib.o a64_fakedylib.s
# RUN: %lld -arch arm64 a64_fakedylib.o -o a64_fakedylib.dylib -dylib

## Create our main testing dylib - linking against the fake dylib above
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-macos -o merge_cat_minimal.o merge_cat_minimal.s
# RUN: %lld -arch arm64 -dylib -o merge_cat_minimal_no_merge.dylib a64_fakedylib.dylib merge_cat_minimal.o
# RUN: %lld -arch arm64 -dylib -o merge_cat_minimal_merge.dylib -objc_category_merging a64_fakedylib.dylib merge_cat_minimal.o

## Now verify that the flag caused category merging to happen appropriatelly
# RUN: llvm-objdump --objc-meta-data --macho merge_cat_minimal_no_merge.dylib | FileCheck %s --check-prefixes=NO_MERGE_CATS
# RUN: llvm-objdump --objc-meta-data --macho merge_cat_minimal_merge.dylib | FileCheck %s --check-prefixes=MERGE_CATS

############ Test merging multiple categories into the base class ############
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-macos -o merge_base_class_minimal.o merge_base_class_minimal.s
# RUN: %lld -arch arm64 -dylib -o merge_base_class_minimal_yes_merge.dylib -objc_category_merging merge_base_class_minimal.o merge_cat_minimal.o
# RUN: %lld -arch arm64 -dylib -o merge_base_class_minimal_no_merge.dylib merge_base_class_minimal.o merge_cat_minimal.o

# RUN: llvm-objdump --objc-meta-data --macho merge_base_class_minimal_no_merge.dylib  | FileCheck %s --check-prefixes=NO_MERGE_INTO_BASE
# RUN: llvm-objdump --objc-meta-data --macho merge_base_class_minimal_yes_merge.dylib | FileCheck %s --check-prefixes=YES_MERGE_INTO_BASE

############ Test merging swift category into the base class ############
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-macos -o MyBaseClassSwiftExtension.o MyBaseClassSwiftExtension.s
# RUN: %lld -no_objc_relative_method_lists -arch arm64 -dylib -o merge_base_class_swift_minimal_yes_merge.dylib -objc_category_merging MyBaseClassSwiftExtension.o merge_base_class_minimal.o
# RUN: llvm-objdump --objc-meta-data --macho merge_base_class_swift_minimal_yes_merge.dylib | FileCheck %s --check-prefixes=YES_MERGE_INTO_BASE_SWIFT

############ Test merging skipped due to invalid category name ############
# Modify __OBJC_$_CATEGORY_MyBaseClass_$_Category01's name to point to L_OBJC_IMAGE_INFO+3
# RUN: awk '/^__OBJC_\$_CATEGORY_MyBaseClass_\$_Category01:/ { print; getline; sub(/^[ \t]*\.quad[ \t]+l_OBJC_CLASS_NAME_$/, "\t.quad\tL_OBJC_IMAGE_INFO+3"); print; next } { print }' merge_cat_minimal.s > merge_cat_minimal_bad_name.s

# Assemble the modified source
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-macos -o merge_cat_minimal_bad_name.o merge_cat_minimal_bad_name.s

# Run lld and check for the specific warning
# RUN: %no-fatal-warnings-lld -arch arm64 -dylib -objc_category_merging -o merge_cat_minimal_merge.dylib a64_fakedylib.dylib merge_cat_minimal_bad_name.o 2>&1 | FileCheck %s --check-prefix=MERGE_WARNING

# Check that lld emitted the warning about skipping category merging
MERGE_WARNING: warning: ObjC category merging skipped for class symbol' _OBJC_CLASS_$_MyBaseClass'

#### Check merge categories enabled ###
# Check that the original categories are not there
MERGE_CATS-NOT: __OBJC_$_CATEGORY_MyBaseClass_$_Category01
MERGE_CATS-NOT: __OBJC_$_CATEGORY_MyBaseClass_$_Category02

# Check that the merged cateogry is there, in the correct format
MERGE_CATS: __OBJC_$_CATEGORY_MyBaseClass(Category01|Category02)
MERGE_CATS-NEXT:   name {{.*}} Category01|Category02
MERGE_CATS:       instanceMethods
MERGE_CATS-NEXT:  entsize 12 (relative)
MERGE_CATS-NEXT:  count 2
MERGE_CATS-NEXT:   name {{.*}} cat01_InstanceMethod
MERGE_CATS-NEXT:  types {{.*}} v16@0:8
MERGE_CATS-NEXT:    imp {{.*}} -[MyBaseClass(Category01) cat01_InstanceMethod]
MERGE_CATS-NEXT:   name {{.*}} cat02_InstanceMethod
MERGE_CATS-NEXT:  types {{.*}} v16@0:8
MERGE_CATS-NEXT:    imp {{.*}} -[MyBaseClass(Category02) cat02_InstanceMethod]
MERGE_CATS-NEXT:         classMethods 0x0
MERGE_CATS-NEXT:            protocols 0x0
MERGE_CATS-NEXT:   instanceProperties 0x0

#### Check merge categories disabled ###
# Check that the merged category is not there
NO_MERGE_CATS-NOT: __OBJC_$_CATEGORY_MyBaseClass(Category01|Category02)

# Check that the original categories are there
NO_MERGE_CATS: __OBJC_$_CATEGORY_MyBaseClass_$_Category01
NO_MERGE_CATS: __OBJC_$_CATEGORY_MyBaseClass_$_Category02


#### Check merge cateogires into base class is disabled ####
NO_MERGE_INTO_BASE: __OBJC_$_CATEGORY_MyBaseClass_$_Category01
NO_MERGE_INTO_BASE: __OBJC_$_CATEGORY_MyBaseClass_$_Category02

#### Check merge cateogires into base class is enabled and categories are merged into base class ####
YES_MERGE_INTO_BASE-NOT: __OBJC_$_CATEGORY_MyBaseClass_$_Category01
YES_MERGE_INTO_BASE-NOT: __OBJC_$_CATEGORY_MyBaseClass_$_Category02

YES_MERGE_INTO_BASE: _OBJC_CLASS_$_MyBaseClass
YES_MERGE_INTO_BASE-NEXT: _OBJC_METACLASS_$_MyBaseClass
YES_MERGE_INTO_BASE: baseMethods
YES_MERGE_INTO_BASE-NEXT: entsize 12 (relative)
YES_MERGE_INTO_BASE-NEXT: count 3
YES_MERGE_INTO_BASE-NEXT: name {{.*}} cat01_InstanceMethod
YES_MERGE_INTO_BASE-NEXT: types {{.*}} v16@0:8
YES_MERGE_INTO_BASE-NEXT: imp {{.*}} -[MyBaseClass(Category01) cat01_InstanceMethod]
YES_MERGE_INTO_BASE-NEXT: name {{.*}} cat02_InstanceMethod
YES_MERGE_INTO_BASE-NEXT: types {{.*}} v16@0:8
YES_MERGE_INTO_BASE-NEXT: imp {{.*}} -[MyBaseClass(Category02) cat02_InstanceMethod]
YES_MERGE_INTO_BASE-NEXT: name {{.*}} baseInstanceMethod
YES_MERGE_INTO_BASE-NEXT: types {{.*}} v16@0:8
YES_MERGE_INTO_BASE-NEXT: imp {{.*}} -[MyBaseClass baseInstanceMethod]


#### Check merge swift category into base class ###
YES_MERGE_INTO_BASE_SWIFT: _OBJC_CLASS_$_MyBaseClass
YES_MERGE_INTO_BASE_SWIFT-NEXT: _OBJC_METACLASS_$_MyBaseClass
YES_MERGE_INTO_BASE_SWIFT: baseMethods
YES_MERGE_INTO_BASE_SWIFT-NEXT: entsize 24
YES_MERGE_INTO_BASE_SWIFT-NEXT: count 2
YES_MERGE_INTO_BASE_SWIFT-NEXT: name {{.*}} swiftMethod
YES_MERGE_INTO_BASE_SWIFT-NEXT: types {{.*}} v16@0:8
YES_MERGE_INTO_BASE_SWIFT-NEXT: imp _$sSo11MyBaseClassC0abC14SwiftExtensionE11swiftMethodyyFTo
YES_MERGE_INTO_BASE_SWIFT-NEXT: name {{.*}} baseInstanceMethod
YES_MERGE_INTO_BASE_SWIFT-NEXT: types {{.*}} v16@0:8
YES_MERGE_INTO_BASE_SWIFT-NEXT: imp -[MyBaseClass baseInstanceMethod]


#--- a64_fakedylib.s

    .section    __DATA,__objc_data
    .globl    _OBJC_CLASS_$_MyBaseClass
_OBJC_CLASS_$_MyBaseClass:
    .quad    0

#--- merge_cat_minimal.s

;  ================== Generated from ObjC: ==================
; __attribute__((objc_root_class))
; @interface MyBaseClass
; - (void)baseInstanceMethod;
; @end
;
; @interface MyBaseClass(Category01)
; - (void)cat01_InstanceMethod;
; @end
;
; @implementation MyBaseClass(Category01)
; - (void)cat01_InstanceMethod {}
; @end
;
; @interface MyBaseClass(Category02)
; - (void)cat02_InstanceMethod;
; @end
;
; @implementation MyBaseClass(Category02)
; - (void)cat02_InstanceMethod {}
; @end
;  ================== Generated from ObjC: ==================

	.section	__TEXT,__text,regular,pure_instructions
	.p2align	2                               ; -- Begin function -[MyBaseClass(Category01) cat01_InstanceMethod]
"-[MyBaseClass(Category01) cat01_InstanceMethod]": ; @"\01-[MyBaseClass(Category01) cat01_InstanceMethod]"
	.cfi_startproc
	ret
	.cfi_endproc
                                        ; -- End function
	.p2align	2                               ; -- Begin function -[MyBaseClass(Category02) cat02_InstanceMethod]
"-[MyBaseClass(Category02) cat02_InstanceMethod]": ; @"\01-[MyBaseClass(Category02) cat02_InstanceMethod]"
	.cfi_startproc
	ret
	.cfi_endproc
                                        ; -- End function
	.section	__TEXT,__objc_classname,cstring_literals
l_OBJC_CLASS_NAME_:                     ; @OBJC_CLASS_NAME_
	.asciz	"Category01"
	.section	__TEXT,__objc_methname,cstring_literals
l_OBJC_METH_VAR_NAME_:                  ; @OBJC_METH_VAR_NAME_
	.asciz	"cat01_InstanceMethod"
	.section	__TEXT,__objc_methtype,cstring_literals
l_OBJC_METH_VAR_TYPE_:                  ; @OBJC_METH_VAR_TYPE_
	.asciz	"v16@0:8"
	.section	__DATA,__objc_const
	.p2align	3, 0x0                          ; @"_OBJC_$_CATEGORY_INSTANCE_METHODS_MyBaseClass_$_Category01"
__OBJC_$_CATEGORY_INSTANCE_METHODS_MyBaseClass_$_Category01:
	.long	24                              ; 0x18
	.long	1                               ; 0x1
	.quad	l_OBJC_METH_VAR_NAME_
	.quad	l_OBJC_METH_VAR_TYPE_
	.quad	"-[MyBaseClass(Category01) cat01_InstanceMethod]"
	.p2align	3, 0x0                          ; @"_OBJC_$_CATEGORY_MyBaseClass_$_Category01"
__OBJC_$_CATEGORY_MyBaseClass_$_Category01:
	.quad	l_OBJC_CLASS_NAME_
	.quad	_OBJC_CLASS_$_MyBaseClass
	.quad	__OBJC_$_CATEGORY_INSTANCE_METHODS_MyBaseClass_$_Category01
	.quad	0
	.quad	0
	.quad	0
	.quad	0
	.long	64                              ; 0x40
	.space	4
	.section	__DATA,__objc_const
l_OBJC_CLASS_NAME_.1:                   ; @OBJC_CLASS_NAME_.1
	.asciz	"Category02"
	.section	__TEXT,__objc_methname,cstring_literals
l_OBJC_METH_VAR_NAME_.2:                ; @OBJC_METH_VAR_NAME_.2
	.asciz	"cat02_InstanceMethod"
	.section	__DATA,__objc_const
	.p2align	3, 0x0                          ; @"_OBJC_$_CATEGORY_INSTANCE_METHODS_MyBaseClass_$_Category02"
__OBJC_$_CATEGORY_INSTANCE_METHODS_MyBaseClass_$_Category02:
	.long	24                              ; 0x18
	.long	1                               ; 0x1
	.quad	l_OBJC_METH_VAR_NAME_.2
	.quad	l_OBJC_METH_VAR_TYPE_
	.quad	"-[MyBaseClass(Category02) cat02_InstanceMethod]"
	.p2align	3, 0x0                          ; @"_OBJC_$_CATEGORY_MyBaseClass_$_Category02"
__OBJC_$_CATEGORY_MyBaseClass_$_Category02:
	.quad	l_OBJC_CLASS_NAME_.1
	.quad	_OBJC_CLASS_$_MyBaseClass
	.quad	__OBJC_$_CATEGORY_INSTANCE_METHODS_MyBaseClass_$_Category02
	.quad	0
	.quad	0
	.quad	0
	.quad	0
	.long	64                              ; 0x40
	.space	4
	.section	__DATA,__objc_catlist,regular,no_dead_strip
	.p2align	3, 0x0                          ; @"OBJC_LABEL_CATEGORY_$"
l_OBJC_LABEL_CATEGORY_$:
	.quad	__OBJC_$_CATEGORY_MyBaseClass_$_Category01
	.quad	__OBJC_$_CATEGORY_MyBaseClass_$_Category02
	.section	__DATA,__objc_imageinfo,regular,no_dead_strip
L_OBJC_IMAGE_INFO:
	.long	0
	.long	96
.subsections_via_symbols

.addrsig
.addrsig_sym __OBJC_$_CATEGORY_MyBaseClass_$_Category01

#--- merge_base_class_minimal.s
; clang -c merge_base_class_minimal.mm -O3 -target arm64-apple-macos -arch arm64 -S -o merge_base_class_minimal.s
;  ================== Generated from ObjC: ==================
; __attribute__((objc_root_class))
; @interface MyBaseClass
; - (void)baseInstanceMethod;
; @end
;
; @implementation MyBaseClass
; - (void)baseInstanceMethod {}
; @end
;  ================== Generated from ObjC  ==================
	.section	__TEXT,__text,regular,pure_instructions
	.build_version macos, 11, 0
	.p2align	2
"-[MyBaseClass baseInstanceMethod]":
	.cfi_startproc
; %bb.0:
	ret
	.cfi_endproc
	.section	__DATA,__objc_data
	.globl	_OBJC_CLASS_$_MyBaseClass
	.p2align	3, 0x0
_OBJC_CLASS_$_MyBaseClass:
	.quad	_OBJC_METACLASS_$_MyBaseClass
	.quad	0
	.quad	0
	.quad	0
	.quad	__OBJC_CLASS_RO_$_MyBaseClass
	.globl	_OBJC_METACLASS_$_MyBaseClass
	.p2align	3, 0x0
_OBJC_METACLASS_$_MyBaseClass:
	.quad	_OBJC_METACLASS_$_MyBaseClass
	.quad	_OBJC_CLASS_$_MyBaseClass
	.quad	0
	.quad	0
	.quad	__OBJC_METACLASS_RO_$_MyBaseClass
	.section	__TEXT,__objc_classname,cstring_literals
l_OBJC_CLASS_NAME_:
	.asciz	"MyBaseClass"
	.section	__DATA,__objc_const
	.p2align	3, 0x0
__OBJC_METACLASS_RO_$_MyBaseClass:
	.long	3
	.long	40
	.long	40
	.space	4
	.quad	0
	.quad	l_OBJC_CLASS_NAME_
	.quad	0
	.quad	0
	.quad	0
	.quad	0
	.quad	0
	.section	__TEXT,__objc_methname,cstring_literals
l_OBJC_METH_VAR_NAME_:
	.asciz	"baseInstanceMethod"
	.section	__TEXT,__objc_methtype,cstring_literals
l_OBJC_METH_VAR_TYPE_:
	.asciz	"v16@0:8"
	.section	__DATA,__objc_const
	.p2align	3, 0x0
__OBJC_$_INSTANCE_METHODS_MyBaseClass:
	.long	24
	.long	1
	.quad	l_OBJC_METH_VAR_NAME_
	.quad	l_OBJC_METH_VAR_TYPE_
	.quad	"-[MyBaseClass baseInstanceMethod]"
	.p2align	3, 0x0
__OBJC_CLASS_RO_$_MyBaseClass:
	.long	2
	.long	0
	.long	0
	.space	4
	.quad	0
	.quad	l_OBJC_CLASS_NAME_
	.quad	__OBJC_$_INSTANCE_METHODS_MyBaseClass
	.quad	0
	.quad	0
	.quad	0
	.quad	0
	.section	__DATA,__objc_classlist,regular,no_dead_strip
	.p2align	3, 0x0
l_OBJC_LABEL_CLASS_$:
	.quad	_OBJC_CLASS_$_MyBaseClass
	.section	__DATA,__objc_imageinfo,regular,no_dead_strip
L_OBJC_IMAGE_INFO:
	.long	0
	.long	64
.subsections_via_symbols


#--- MyBaseClassSwiftExtension.s
; xcrun -sdk macosx swiftc -emit-assembly MyBaseClassSwiftExtension.swift -import-objc-header YourProject-Bridging-Header.h -o MyBaseClassSwiftExtension.s
;  ================== Generated from Swift: ==================
; import Foundation
; extension MyBaseClass {
;     @objc func swiftMethod() {
;     }
; }
;  ================== Generated from Swift ===================
	.private_extern	_$sSo11MyBaseClassC0abC14SwiftExtensionE11swiftMethodyyF
	.globl	_$sSo11MyBaseClassC0abC14SwiftExtensionE11swiftMethodyyF
	.p2align	2
_$sSo11MyBaseClassC0abC14SwiftExtensionE11swiftMethodyyF:
	.cfi_startproc
	mov	w0, #0
	ret
	.cfi_endproc

	.p2align	2
_$sSo11MyBaseClassC0abC14SwiftExtensionE11swiftMethodyyFTo:
	.cfi_startproc
	mov	w0, #0
	ret
	.cfi_endproc

	.section	__TEXT,__cstring,cstring_literals
	.p2align	4, 0x0
l_.str.25.MyBaseClassSwiftExtension:
	.asciz	"MyBaseClassSwiftExtension"

	.section	__TEXT,__objc_methname,cstring_literals
"L_selector_data(swiftMethod)":
	.asciz	"swiftMethod"

	.section	__TEXT,__cstring,cstring_literals
"l_.str.7.v16@0:8":
	.asciz	"v16@0:8"

	.section	__DATA,__objc_data
	.p2align	3, 0x0
__CATEGORY_INSTANCE_METHODS_MyBaseClass_$_MyBaseClassSwiftExtension:
	.long	24
	.long	1
	.quad	"L_selector_data(swiftMethod)"
	.quad	"l_.str.7.v16@0:8"
	.quad	_$sSo11MyBaseClassC0abC14SwiftExtensionE11swiftMethodyyFTo

	.section	__DATA,__objc_const
	.p2align	3, 0x0
__CATEGORY_MyBaseClass_$_MyBaseClassSwiftExtension:
	.quad	l_.str.25.MyBaseClassSwiftExtension
	.quad	_OBJC_CLASS_$_MyBaseClass
	.quad	__CATEGORY_INSTANCE_METHODS_MyBaseClass_$_MyBaseClassSwiftExtension
	.quad	0
	.quad	0
	.quad	0
	.quad	0
	.long	60
	.space	4

	.section	__DATA,__objc_catlist,regular,no_dead_strip
	.p2align	3, 0x0
_objc_categories:
	.quad	__CATEGORY_MyBaseClass_$_MyBaseClassSwiftExtension

	.no_dead_strip	_main
	.no_dead_strip	l_entry_point

.subsections_via_symbols
