@@ -39,6 +39,8 @@ STATISTIC(FailInferFunction, "# of functions unable to infer");
39
39
// Specifically skipped/avoided
40
40
STATISTIC (SkipLeadingUnderscore,
41
41
" # of globals skipped due to leading underscore" );
42
+ STATISTIC (SkipCFMemoryManagement,
43
+ " # of CF memory management globals skipped" );
42
44
43
45
// Success statistics
44
46
STATISTIC (SuccessImportAsTypeID, " # imported as 'typeID'" );
@@ -176,6 +178,7 @@ class IAMInference {
176
178
}
177
179
178
180
IAMResult infer (const clang::NamedDecl *);
181
+ IAMResult inferVar (const clang::VarDecl *);
179
182
180
183
private:
181
184
// typeID
@@ -536,40 +539,42 @@ static bool roughlyEqual(clang::QualType left, clang::QualType right) {
536
539
right->getUnqualifiedDesugaredType ();
537
540
}
538
541
539
- bool IAMInference::validToImportAsProperty (
540
- const clang::FunctionDecl *originalDecl, StringRef propSpec,
541
- Optional<unsigned > selfIndex, const clang::FunctionDecl *&pairedAccessor) {
542
- bool isGet = propSpec == " Get" ;
543
- pairedAccessor = findPairedAccessor (originalDecl->getName (), propSpec);
544
- if (!pairedAccessor)
545
- return isGet;
542
+ static bool
543
+ isValidAsStaticProperty (const clang::FunctionDecl *getterDecl,
544
+ const clang::FunctionDecl *setterDecl = nullptr ) {
545
+ // Getter has none, setter has one arg
546
+ if (getterDecl->getNumParams () != 0 ||
547
+ (setterDecl && setterDecl->getNumParams () != 1 )) {
548
+ ++InvalidPropertyStaticNumParams;
549
+ return false ;
550
+ }
546
551
547
- auto getterDecl = isGet ? originalDecl : pairedAccessor;
548
- auto setterDecl = isGet ? pairedAccessor : originalDecl;
552
+ // Setter's arg type should be same as getter's return type
549
553
auto getterTy = getterDecl->getReturnType ();
550
-
551
- // See if this is a static property
552
- if (!selfIndex) {
553
- // Getter has none, setter has one arg
554
- if (getterDecl->getNumParams () != 0 || setterDecl->getNumParams () != 1 ) {
555
- ++InvalidPropertyStaticNumParams;
556
- return false ;
557
- }
558
-
559
- // Setter's arg type should be same as getter's return type
560
- if (!roughlyEqual (getterTy, setterDecl->getParamDecl (0 )->getType ())) {
561
- ++InvalidPropertyStaticGetterSetterType;
562
- return false ;
563
- }
564
-
565
- return true ;
554
+ if (setterDecl &&
555
+ !roughlyEqual (getterTy, setterDecl->getParamDecl (0 )->getType ())) {
556
+ ++InvalidPropertyStaticGetterSetterType;
557
+ return false ;
566
558
}
567
559
560
+ return true ;
561
+ }
562
+
563
+ static bool
564
+ isValidAsInstanceProperty (const clang::FunctionDecl *getterDecl,
565
+ const clang::FunctionDecl *setterDecl = nullptr ) {
568
566
// Instance property, look beyond self
569
- if (getterDecl->getNumParams () != 1 || setterDecl->getNumParams () != 2 ) {
567
+ if (getterDecl->getNumParams () != 1 ||
568
+ (setterDecl && setterDecl->getNumParams () != 2 )) {
570
569
++InvalidPropertyInstanceNumParams;
571
570
return false ;
572
571
}
572
+
573
+ if (!setterDecl)
574
+ return true ;
575
+
576
+ // Make sure they pair up
577
+ auto getterTy = getterDecl->getReturnType ();
573
578
auto selfTy = getterDecl->getParamDecl (0 )->getType ();
574
579
575
580
clang::QualType setterTy = {};
@@ -593,39 +598,65 @@ bool IAMInference::validToImportAsProperty(
593
598
return true ;
594
599
}
595
600
596
- IAMResult IAMInference::infer (const clang::NamedDecl *clangDecl) {
597
- if (clangDecl->getName ().startswith (" _" )) {
598
- ++SkipLeadingUnderscore;
599
- return {};
601
+ bool IAMInference::validToImportAsProperty (
602
+ const clang::FunctionDecl *originalDecl, StringRef propSpec,
603
+ Optional<unsigned > selfIndex, const clang::FunctionDecl *&pairedAccessor) {
604
+ bool isGet = propSpec == " Get" ;
605
+ pairedAccessor = findPairedAccessor (originalDecl->getName (), propSpec);
606
+ if (!pairedAccessor) {
607
+ if (!isGet)
608
+ return false ;
609
+ if (!selfIndex)
610
+ return isValidAsStaticProperty (originalDecl);
611
+ return isValidAsInstanceProperty (originalDecl);
600
612
}
601
613
602
- if (auto varDecl = dyn_cast<clang::VarDecl>(clangDecl)) {
603
- auto fail = [varDecl]() -> IAMResult {
604
- DEBUG (llvm::dbgs () << " failed to infer variable: " );
605
- DEBUG (varDecl->print (llvm::dbgs ()));
606
- DEBUG (llvm::dbgs () << " \n " );
607
- ++FailInferVar;
608
- return {};
609
- };
610
-
611
- // Try to find a type to add this as a static property to
612
- StringRef workingName = varDecl->getName ();
613
- if (workingName.empty ())
614
- return fail ();
614
+ auto getterDecl = isGet ? originalDecl : pairedAccessor;
615
+ auto setterDecl = isGet ? pairedAccessor : originalDecl;
615
616
616
- // Special pattern: constants of the form "kFooBarBaz", extend "FooBar" with
617
- // property "Baz"
618
- if (*camel_case::getWords (workingName).begin () == " k" )
619
- workingName = workingName.drop_front (1 );
617
+ if (!selfIndex)
618
+ return isValidAsStaticProperty (getterDecl, setterDecl);
620
619
621
- NameBuffer remainingName ;
622
- if ( auto effectiveDC = findTypeAndMatch (workingName, remainingName))
620
+ return isValidAsInstanceProperty (getterDecl, setterDecl) ;
621
+ }
623
622
624
- return importAsStaticProperty (remainingName, effectiveDC);
623
+ IAMResult IAMInference::inferVar (const clang::VarDecl *varDecl) {
624
+ auto fail = [varDecl]() -> IAMResult {
625
+ DEBUG (llvm::dbgs () << " failed to infer variable: " );
626
+ DEBUG (varDecl->print (llvm::dbgs ()));
627
+ DEBUG (llvm::dbgs () << " \n " );
628
+ ++FailInferVar;
629
+ return {};
630
+ };
625
631
632
+ // Try to find a type to add this as a static property to
633
+ StringRef workingName = varDecl->getName ();
634
+ if (workingName.empty ())
626
635
return fail ();
636
+
637
+ // Special pattern: constants of the form "kFooBarBaz", extend "FooBar" with
638
+ // property "Baz"
639
+ if (*camel_case::getWords (workingName).begin () == " k" )
640
+ workingName = workingName.drop_front (1 );
641
+
642
+ NameBuffer remainingName;
643
+ if (auto effectiveDC = findTypeAndMatch (workingName, remainingName))
644
+
645
+ return importAsStaticProperty (remainingName, effectiveDC);
646
+
647
+ return fail ();
648
+ }
649
+
650
+ IAMResult IAMInference::infer (const clang::NamedDecl *clangDecl) {
651
+ if (clangDecl->getName ().startswith (" _" )) {
652
+ ++SkipLeadingUnderscore;
653
+ return {};
627
654
}
628
655
656
+ // Try to infer a member variable
657
+ if (auto varDecl = dyn_cast<clang::VarDecl>(clangDecl))
658
+ return inferVar (varDecl);
659
+
629
660
// Try to infer a member function
630
661
auto funcDecl = dyn_cast<clang::FunctionDecl>(clangDecl);
631
662
if (!funcDecl) {
@@ -651,9 +682,11 @@ IAMResult IAMInference::infer(const clang::NamedDecl *clangDecl) {
651
682
auto retTy = funcDecl->getReturnType ();
652
683
unsigned numParams = funcDecl->getNumParams ();
653
684
654
- // 0) Special cases are specially handled: *GetTypeID()
685
+ // 0) Special cases are specially handled
655
686
//
656
687
StringRef getTypeID = " GetTypeID" ;
688
+ StringRef cfSpecials[] = {" Release" , " Retain" , " Autorelease" };
689
+ // *GetTypeID
657
690
if (numParams == 0 && workingName.endswith (getTypeID)) {
658
691
NameBuffer remainingName;
659
692
if (auto effectiveDC = findTypeAndMatch (
@@ -664,6 +697,19 @@ IAMResult IAMInference::infer(const clang::NamedDecl *clangDecl) {
664
697
return importAsTypeID (retTy, effectiveDC);
665
698
}
666
699
}
700
+ // *Release/*Retain/*Autorelease
701
+ } else if (numParams == 1 &&
702
+ std::any_of (std::begin (cfSpecials), std::end (cfSpecials),
703
+ [workingName](StringRef suffix) {
704
+ return workingName.endswith (suffix);
705
+ })) {
706
+ if (auto type =
707
+ funcDecl->getParamDecl (0 )->getType ()->getAs <clang::TypedefType>()) {
708
+ if (CFPointeeInfo::classifyTypedef (type->getDecl ())) {
709
+ ++SkipCFMemoryManagement;
710
+ return {};
711
+ }
712
+ }
667
713
}
668
714
669
715
// 1) If we find an init specifier and our name matches the return type, we
0 commit comments