Author: arphaman Date: Wed Jul 26 06:58:02 2017 New Revision: 309116 URL: http://llvm.org/viewvc/llvm-project?rev=309116&view=rev Log: unguarded availability: add a fixit for the "annotate '...' with an availability attribute to silence" note
rdar://33539233 Differential Revision: https://reviews.llvm.org/D35726 Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp cfe/trunk/test/FixIt/fixit-availability.c cfe/trunk/test/FixIt/fixit-availability.mm Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=309116&r1=309115&r2=309116&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Wed Jul 26 06:58:02 2017 @@ -7032,6 +7032,49 @@ static NamedDecl *findEnclosingDeclToAnn return dyn_cast<NamedDecl>(OrigCtx); } +namespace { + +struct AttributeInsertion { + StringRef Prefix; + SourceLocation Loc; + StringRef Suffix; + + static AttributeInsertion createInsertionAfter(const NamedDecl *D) { + return {" ", D->getLocEnd(), ""}; + } + static AttributeInsertion createInsertionAfter(SourceLocation Loc) { + return {" ", Loc, ""}; + } + static AttributeInsertion createInsertionBefore(const NamedDecl *D) { + return {"", D->getLocStart(), "\n"}; + } +}; + +} // end anonymous namespace + +/// Returns a source location in which it's appropriate to insert a new +/// attribute for the given declaration \D. +static Optional<AttributeInsertion> +createAttributeInsertion(const NamedDecl *D, const SourceManager &SM, + const LangOptions &LangOpts) { + if (isa<ObjCPropertyDecl>(D)) + return AttributeInsertion::createInsertionAfter(D); + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (MD->hasBody()) + return None; + return AttributeInsertion::createInsertionAfter(D); + } + if (const auto *TD = dyn_cast<TagDecl>(D)) { + SourceLocation Loc = + Lexer::getLocForEndOfToken(TD->getInnerLocStart(), 0, SM, LangOpts); + if (Loc.isInvalid()) + return None; + // Insert after the 'struct'/whatever keyword. + return AttributeInsertion::createInsertionAfter(Loc); + } + return AttributeInsertion::createInsertionBefore(D); +} + /// Actually emit an availability diagnostic for a reference to an unavailable /// decl. /// @@ -7221,8 +7264,29 @@ static void DoEmitAvailabilityWarning(Se << /*Anonymous*/1 << TD->getKindName(); return; } - S.Diag(Enclosing->getLocation(), diag::note_partial_availability_silence) - << /*Named*/0 << Enclosing; + auto FixitNoteDiag = S.Diag(Enclosing->getLocation(), + diag::note_partial_availability_silence) + << /*Named*/ 0 << Enclosing; + // Don't offer a fixit for declarations with availability attributes. + if (Enclosing->hasAttr<AvailabilityAttr>()) + return; + if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE")) + return; + Optional<AttributeInsertion> Insertion = createAttributeInsertion( + Enclosing, S.getSourceManager(), S.getLangOpts()); + if (!Insertion) + return; + std::string PlatformName = + AvailabilityAttr::getPlatformNameSourceSpelling( + S.getASTContext().getTargetInfo().getPlatformName()) + .lower(); + std::string Introduced = + OffendingDecl->getVersionIntroduced().getAsString(); + FixitNoteDiag << FixItHint::CreateInsertion( + Insertion->Loc, + (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" + PlatformName + + "(" + Introduced + "))" + Insertion->Suffix) + .str()); } } Modified: cfe/trunk/test/FixIt/fixit-availability.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit-availability.c?rev=309116&r1=309115&r2=309116&view=diff ============================================================================== --- cfe/trunk/test/FixIt/fixit-availability.c (original) +++ cfe/trunk/test/FixIt/fixit-availability.c Wed Jul 26 06:58:02 2017 @@ -8,3 +8,11 @@ void use() { // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"if (__builtin_available(macOS 10.12, *)) {\n " // CHECK-NEXT: fix-it:{{.*}}:{[[@LINE-2]]:14-[[@LINE-2]]:14}:"\n } else {\n // Fallback on earlier versions\n }" } + +__attribute__((availability(macos, introduced=10.12))) +struct New { }; + +struct NoFixit { + struct New field; +}; +// CHECK-NOT: API_AVAILABLE Modified: cfe/trunk/test/FixIt/fixit-availability.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit-availability.mm?rev=309116&r1=309115&r2=309116&view=diff ============================================================================== --- cfe/trunk/test/FixIt/fixit-availability.mm (original) +++ cfe/trunk/test/FixIt/fixit-availability.mm Wed Jul 26 06:58:02 2017 @@ -109,3 +109,34 @@ void wrapDeclStmtUses() { anotherFunction(y); anotherFunction(x); } + +#define API_AVAILABLE(X) __attribute__((availability(macos, introduced=10.12))) // dummy macro + +API_AVAILABLE(macos(10.12)) +@interface NewClass +@end + +@interface OldButOfferFixit +@property(copy) NewClass *prop; +// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:1-[[@LINE-2]]:1}:"API_AVAILABLE(macos(10.12))\n" + +- (NewClass *)fixitMe; +// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:22-[[@LINE-1]]:22}:" API_AVAILABLE(macos(10.12))" +@end + +void oldButOfferFixitFn(NewClass *) { +// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"API_AVAILABLE(macos(10.12))\n" +} + +template<typename T> +struct OldButOfferFixitTag { +// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:7-[[@LINE-1]]:7}:" API_AVAILABLE(macos(10.12))" + NewClass *x; +}; + +// Avoid a fixit for declarations that already have an attribute: +__attribute__((availability(macos, introduced=10.11))) +@interface WithoutFixit +@property(copy) NewClass *prop; +// CHECK-NOT: API_AVAILABLE +@end _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits