Skip to content

Commit

Permalink
Reapply r277058: "[ObjC] Consider availability of context when emitti…
Browse files Browse the repository at this point in the history
…ng availability warnings"

llvm-svn: 277175
  • Loading branch information
epilk committed Jul 29, 2016
1 parent 99e39a7 commit 48c7cc9
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 21 deletions.
8 changes: 7 additions & 1 deletion clang/include/clang/AST/DeclBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "clang/AST/AttrIterator.h"
#include "clang/AST/DeclarationName.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/iterator_range.h"
Expand Down Expand Up @@ -603,7 +604,12 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
/// AR_Available, will be set to a (possibly empty) message
/// describing why the declaration has not been introduced, is
/// deprecated, or is unavailable.
AvailabilityResult getAvailability(std::string *Message = nullptr) const;
///
/// \param EnclosingVersion The version to compare with. If empty, assume the
/// deployment target version.
AvailabilityResult
getAvailability(std::string *Message = nullptr,
VersionTuple EnclosingVersion = VersionTuple()) const;

/// \brief Determine whether this declaration is marked 'deprecated'.
///
Expand Down
7 changes: 6 additions & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -9596,7 +9596,12 @@ class Sema {
}

AvailabilityResult getCurContextAvailability() const;


/// \brief Get the verison that this context implies.
/// For instance, a method in an interface that is annotated with an
/// availability attribuite effectively has the availability of the interface.
VersionTuple getVersionForDecl(const Decl *Ctx) const;

const DeclContext *getCurObjCLexicalContext() const {
const DeclContext *DC = getCurLexicalContext();
// A category implicitly has the attribute of the interface.
Expand Down
26 changes: 14 additions & 12 deletions clang/lib/AST/DeclBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,11 +400,12 @@ const Attr *Decl::getDefiningAttr() const {
/// diagnostics.
static AvailabilityResult CheckAvailability(ASTContext &Context,
const AvailabilityAttr *A,
std::string *Message) {
VersionTuple TargetMinVersion =
Context.getTargetInfo().getPlatformMinVersion();
std::string *Message,
VersionTuple EnclosingVersion) {
if (EnclosingVersion.empty())
EnclosingVersion = Context.getTargetInfo().getPlatformMinVersion();

if (TargetMinVersion.empty())
if (EnclosingVersion.empty())
return AR_Available;

// Check if this is an App Extension "platform", and if so chop off
Expand Down Expand Up @@ -449,7 +450,7 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,

// Make sure that this declaration has already been introduced.
if (!A->getIntroduced().empty() &&
TargetMinVersion < A->getIntroduced()) {
EnclosingVersion < A->getIntroduced()) {
if (Message) {
Message->clear();
llvm::raw_string_ostream Out(*Message);
Expand All @@ -463,7 +464,7 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
}

// Make sure that this declaration hasn't been obsoleted.
if (!A->getObsoleted().empty() && TargetMinVersion >= A->getObsoleted()) {
if (!A->getObsoleted().empty() && EnclosingVersion >= A->getObsoleted()) {
if (Message) {
Message->clear();
llvm::raw_string_ostream Out(*Message);
Expand All @@ -477,7 +478,7 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
}

// Make sure that this declaration hasn't been deprecated.
if (!A->getDeprecated().empty() && TargetMinVersion >= A->getDeprecated()) {
if (!A->getDeprecated().empty() && EnclosingVersion >= A->getDeprecated()) {
if (Message) {
Message->clear();
llvm::raw_string_ostream Out(*Message);
Expand All @@ -493,9 +494,10 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
return AR_Available;
}

AvailabilityResult Decl::getAvailability(std::string *Message) const {
AvailabilityResult Decl::getAvailability(std::string *Message,
VersionTuple EnclosingVersion) const {
if (auto *FTD = dyn_cast<FunctionTemplateDecl>(this))
return FTD->getTemplatedDecl()->getAvailability(Message);
return FTD->getTemplatedDecl()->getAvailability(Message, EnclosingVersion);

AvailabilityResult Result = AR_Available;
std::string ResultMessage;
Expand All @@ -520,7 +522,7 @@ AvailabilityResult Decl::getAvailability(std::string *Message) const {

if (const auto *Availability = dyn_cast<AvailabilityAttr>(A)) {
AvailabilityResult AR = CheckAvailability(getASTContext(), Availability,
Message);
Message, EnclosingVersion);

if (AR == AR_Unavailable)
return AR_Unavailable;
Expand Down Expand Up @@ -579,8 +581,8 @@ bool Decl::isWeakImported() const {
return true;

if (const auto *Availability = dyn_cast<AvailabilityAttr>(A)) {
if (CheckAvailability(getASTContext(), Availability,
nullptr) == AR_NotYetIntroduced)
if (CheckAvailability(getASTContext(), Availability, nullptr,
VersionTuple()) == AR_NotYetIntroduced)
return true;
}
}
Expand Down
23 changes: 23 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6484,3 +6484,26 @@ void Sema::EmitAvailabilityWarning(AvailabilityDiagnostic AD,
DoEmitAvailabilityWarning(*this, AD, Ctx, D, Message, Loc, UnknownObjCClass,
ObjCProperty, ObjCPropertyAccess);
}

VersionTuple Sema::getVersionForDecl(const Decl *D) const {
assert(D && "Expected a declaration here!");

VersionTuple DeclVersion;
if (const auto *AA = getAttrForPlatform(getASTContext(), D))
DeclVersion = AA->getIntroduced();

const ObjCInterfaceDecl *Interface = nullptr;

if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
Interface = MD->getClassInterface();
else if (const auto *ID = dyn_cast<ObjCImplementationDecl>(D))
Interface = ID->getClassInterface();

if (Interface) {
if (const auto *AA = getAttrForPlatform(getASTContext(), Interface))
if (AA->getIntroduced() > DeclVersion)
DeclVersion = AA->getIntroduced();
}

return DeclVersion;
}
20 changes: 13 additions & 7 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,17 +107,22 @@ static AvailabilityResult
DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass,
bool ObjCPropertyAccess) {
// See if this declaration is unavailable or deprecated.
VersionTuple ContextVersion;
if (const DeclContext *DC = S.getCurObjCLexicalContext())
ContextVersion = S.getVersionForDecl(cast<Decl>(DC));

// See if this declaration is unavailable, deprecated, or partial in the
// current context.
std::string Message;
AvailabilityResult Result = D->getAvailability(&Message);
AvailabilityResult Result = D->getAvailability(&Message, ContextVersion);

// For typedefs, if the typedef declaration appears available look
// to the underlying type to see if it is more restrictive.
while (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
if (Result == AR_Available) {
if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) {
D = TT->getDecl();
Result = D->getAvailability(&Message);
Result = D->getAvailability(&Message, ContextVersion);
continue;
}
}
Expand All @@ -128,23 +133,24 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc,
if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
if (IDecl->getDefinition()) {
D = IDecl->getDefinition();
Result = D->getAvailability(&Message);
Result = D->getAvailability(&Message, ContextVersion);
}
}

if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D))
if (Result == AR_Available) {
const DeclContext *DC = ECD->getDeclContext();
if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC))
Result = TheEnumDecl->getAvailability(&Message);
Result = TheEnumDecl->getAvailability(&Message, ContextVersion);
}

const ObjCPropertyDecl *ObjCPDecl = nullptr;
if (Result == AR_Deprecated || Result == AR_Unavailable ||
Result == AR_NotYetIntroduced) {
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
AvailabilityResult PDeclResult =
PD->getAvailability(nullptr, ContextVersion);
if (PDeclResult == Result)
ObjCPDecl = PD;
}
Expand Down Expand Up @@ -198,7 +204,7 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc,
break;

}
return Result;
return Result;
}

/// \brief Emit a note explaining that this function is deleted.
Expand Down
31 changes: 31 additions & 0 deletions clang/test/SemaObjC/attr-availability.m
Original file line number Diff line number Diff line change
Expand Up @@ -294,3 +294,34 @@ -(void)method {
[obj method]; // expected-error{{'method' is unavailable}}
}
@end

#if defined(WARN_PARTIAL)

int fn_10_7() __attribute__((availability(macosx, introduced=10.7))); // expected-note{{marked partial here}}
int fn_10_8() __attribute__((availability(macosx, introduced=10.8))) { // expected-note{{marked partial here}}
return fn_10_7();
}

__attribute__((objc_root_class))
@interface LookupAvailabilityBase
-(void) method1;
@end

@implementation LookupAvailabilityBase
-(void)method1 { fn_10_7(); } // expected-warning{{partial}} expected-note{{explicitly redeclare}}
@end

__attribute__((availability(macosx, introduced=10.7)))
@interface LookupAvailability : LookupAvailabilityBase
- (void)method2;
- (void)method3;
- (void)method4 __attribute__((availability(macosx, introduced=10.8)));
@end

@implementation LookupAvailability
-(void)method2 { fn_10_7(); }
-(void)method3 { fn_10_8(); } // expected-warning{{partial}} expected-note{{explicitly redeclare}}
-(void)method4 { fn_10_8(); }
@end

#endif

0 comments on commit 48c7cc9

Please sign in to comment.