@@ -2647,43 +2647,46 @@ ArgumentAttrs ClangImporter::Implementation::inferDefaultArgument(
2647
2647
} else if (const clang::TypedefType *typedefType =
2648
2648
type->getAs <clang::TypedefType>()) {
2649
2649
// Get the AvailabilityAttr that would be set from CF/NS_OPTIONS
2650
- if (importer::isUnavailableInSwift (typedefType->getDecl (), nullptr , true )) {
2650
+ clang::TypedefNameDecl *typedefDecl = typedefType->getDecl ();
2651
+ if (importer::isUnavailableInSwift (typedefDecl, nullptr , true )) {
2651
2652
// If we've taken this branch it means we have an enum type, and it is
2652
2653
// likely an integer or NSInteger that is being used by NS/CF_OPTIONS to
2653
2654
// behave like a C enum in the presence of C++.
2654
- auto enumName = typedefType->getDecl ()->getName ();
2655
- ArgumentAttrs argumentAttrs (DefaultArgumentKind::None, true , enumName);
2656
- auto camelCaseWords = camel_case::getWords (enumName);
2657
- for (auto it = camelCaseWords.rbegin (); it != camelCaseWords.rend ();
2658
- ++it) {
2659
- auto word = *it;
2660
- auto next = std::next (it);
2661
- if (camel_case::sameWordIgnoreFirstCase (word, " options" )) {
2662
- argumentAttrs.argumentKind = DefaultArgumentKind::EmptyArray;
2663
- return argumentAttrs;
2655
+ auto enumName = typedefDecl->getName ();
2656
+ // Find the next decl in the same context. If this typedef is a part of an
2657
+ // NS/CF_OPTIONS declaration, the next decl will be an enum.
2658
+ auto declsInContext = typedefDecl->getDeclContext ()->decls ();
2659
+ auto declIter = llvm::find (declsInContext, typedefDecl);
2660
+ if (declIter != declsInContext.end ())
2661
+ declIter++;
2662
+ if (declIter != declsInContext.end ()) {
2663
+ if (auto enumDecl = dyn_cast<clang::EnumDecl>(*declIter)) {
2664
+ // If this is a NS/CF_OPTIONS declaration, the enum will have no name,
2665
+ // and all enum cases will likely be prefixed with the name of the
2666
+ // enum.
2667
+ bool looksLikeCFOptions =
2668
+ !enumDecl->getIdentifier () &&
2669
+ enumDecl->hasAttr <clang::FlagEnumAttr>() &&
2670
+ enumDecl->hasAttr <clang::EnumExtensibilityAttr>();
2671
+ if (looksLikeCFOptions) {
2672
+ for (auto caseDecl : enumDecl->enumerators ()) {
2673
+ if (!caseDecl->getName ().starts_with (enumName)) {
2674
+ looksLikeCFOptions = false ;
2675
+ break ;
2676
+ }
2677
+ }
2678
+ }
2679
+ if (looksLikeCFOptions) {
2680
+ ArgumentAttrs argumentAttrs (DefaultArgumentKind::None, true ,
2681
+ enumName);
2682
+ for (auto word : llvm::reverse (camel_case::getWords (enumName))) {
2683
+ if (camel_case::sameWordIgnoreFirstCase (word, " options" )) {
2684
+ argumentAttrs.argumentKind = DefaultArgumentKind::EmptyArray;
2685
+ }
2686
+ }
2687
+ return argumentAttrs;
2688
+ }
2664
2689
}
2665
- if (camel_case::sameWordIgnoreFirstCase (word, " units" ))
2666
- return argumentAttrs;
2667
- if (camel_case::sameWordIgnoreFirstCase (word, " domain" ))
2668
- return argumentAttrs;
2669
- if (camel_case::sameWordIgnoreFirstCase (word, " action" ))
2670
- return argumentAttrs;
2671
- if (camel_case::sameWordIgnoreFirstCase (word, " event" ))
2672
- return argumentAttrs;
2673
- if (camel_case::sameWordIgnoreFirstCase (word, " events" ) &&
2674
- next != camelCaseWords.rend () &&
2675
- camel_case::sameWordIgnoreFirstCase (*next, " control" ))
2676
- return argumentAttrs;
2677
- if (camel_case::sameWordIgnoreFirstCase (word, " state" ))
2678
- return argumentAttrs;
2679
- if (camel_case::sameWordIgnoreFirstCase (word, " unit" ))
2680
- return argumentAttrs;
2681
- if (camel_case::sameWordIgnoreFirstCase (word, " position" ) &&
2682
- next != camelCaseWords.rend () &&
2683
- camel_case::sameWordIgnoreFirstCase (*next, " scroll" ))
2684
- return argumentAttrs;
2685
- if (camel_case::sameWordIgnoreFirstCase (word, " edge" ))
2686
- return argumentAttrs;
2687
2690
}
2688
2691
}
2689
2692
}
0 commit comments