2017-11-23 05:32:07 +08:00
|
|
|
//===- DeclObjC.cpp - ObjC Declaration AST Node Implementation ------------===//
|
2008-03-16 08:19:01 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2008-03-16 08:19:01 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the Objective-C related Decl classes.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "clang/AST/DeclObjC.h"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
2011-09-01 08:58:55 +08:00
|
|
|
#include "clang/AST/ASTMutationListener.h"
|
2012-12-01 23:09:41 +08:00
|
|
|
#include "clang/AST/Attr.h"
|
2017-11-23 05:32:07 +08:00
|
|
|
#include "clang/AST/Decl.h"
|
|
|
|
#include "clang/AST/DeclBase.h"
|
2012-12-01 23:09:41 +08:00
|
|
|
#include "clang/AST/Stmt.h"
|
2017-11-23 05:32:07 +08:00
|
|
|
#include "clang/AST/Type.h"
|
|
|
|
#include "clang/AST/TypeLoc.h"
|
|
|
|
#include "clang/Basic/IdentifierTable.h"
|
|
|
|
#include "clang/Basic/LLVM.h"
|
|
|
|
#include "clang/Basic/LangOptions.h"
|
|
|
|
#include "clang/Basic/SourceLocation.h"
|
|
|
|
#include "llvm/ADT/None.h"
|
2012-09-28 03:45:11 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2017-11-23 05:32:07 +08:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <cstring>
|
2020-02-28 07:57:44 +08:00
|
|
|
#include <queue>
|
2017-11-23 05:32:07 +08:00
|
|
|
#include <utility>
|
|
|
|
|
2008-03-16 08:19:01 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2009-02-21 05:16:26 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ObjCListBase
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-02-21 05:35:13 +08:00
|
|
|
void ObjCListBase::set(void *const* InList, unsigned Elts, ASTContext &Ctx) {
|
2014-05-12 13:36:57 +08:00
|
|
|
List = nullptr;
|
2009-02-21 05:16:26 +08:00
|
|
|
if (Elts == 0) return; // Setting to an empty list is a noop.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-21 05:44:01 +08:00
|
|
|
List = new (Ctx) void*[Elts];
|
2009-02-21 05:16:26 +08:00
|
|
|
NumElts = Elts;
|
|
|
|
memcpy(List, InList, sizeof(void*)*Elts);
|
|
|
|
}
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
void ObjCProtocolList::set(ObjCProtocolDecl* const* InList, unsigned Elts,
|
2010-01-16 23:02:53 +08:00
|
|
|
const SourceLocation *Locs, ASTContext &Ctx) {
|
|
|
|
if (Elts == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Locations = new (Ctx) SourceLocation[Elts];
|
|
|
|
memcpy(Locations, Locs, sizeof(SourceLocation) * Elts);
|
|
|
|
set(InList, Elts, Ctx);
|
|
|
|
}
|
|
|
|
|
2008-03-16 08:49:28 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2009-02-21 04:59:54 +08:00
|
|
|
// ObjCInterfaceDecl
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-08-02 05:31:08 +08:00
|
|
|
ObjCContainerDecl::ObjCContainerDecl(Kind DK, DeclContext *DC,
|
|
|
|
IdentifierInfo *Id, SourceLocation nameLoc,
|
|
|
|
SourceLocation atStartLoc)
|
|
|
|
: NamedDecl(DK, DC, nameLoc, Id), DeclContext(DK) {
|
|
|
|
setAtStartLoc(atStartLoc);
|
|
|
|
}
|
|
|
|
|
2017-11-23 05:32:07 +08:00
|
|
|
void ObjCContainerDecl::anchor() {}
|
2011-12-20 10:48:34 +08:00
|
|
|
|
2009-06-06 02:16:35 +08:00
|
|
|
/// getIvarDecl - This method looks up an ivar in this ContextDecl.
|
|
|
|
///
|
|
|
|
ObjCIvarDecl *
|
2009-06-30 10:36:12 +08:00
|
|
|
ObjCContainerDecl::getIvarDecl(IdentifierInfo *Id) const {
|
2015-02-21 10:45:19 +08:00
|
|
|
lookup_result R = lookup(Id);
|
|
|
|
for (lookup_iterator Ivar = R.begin(), IvarEnd = R.end();
|
2012-12-19 08:45:41 +08:00
|
|
|
Ivar != IvarEnd; ++Ivar) {
|
2018-04-10 06:14:10 +08:00
|
|
|
if (auto *ivar = dyn_cast<ObjCIvarDecl>(*Ivar))
|
2009-06-06 02:16:35 +08:00
|
|
|
return ivar;
|
|
|
|
}
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2009-06-06 02:16:35 +08:00
|
|
|
}
|
|
|
|
|
2009-07-26 06:15:22 +08:00
|
|
|
// Get the local instance/class method declared in this interface.
|
2009-04-10 05:40:53 +08:00
|
|
|
ObjCMethodDecl *
|
2013-03-30 05:51:48 +08:00
|
|
|
ObjCContainerDecl::getMethod(Selector Sel, bool isInstance,
|
|
|
|
bool AllowHidden) const {
|
2013-01-17 08:38:46 +08:00
|
|
|
// If this context is a hidden protocol definition, don't find any
|
|
|
|
// methods there.
|
2018-04-10 06:14:10 +08:00
|
|
|
if (const auto *Proto = dyn_cast<ObjCProtocolDecl>(this)) {
|
2013-01-17 08:38:46 +08:00
|
|
|
if (const ObjCProtocolDecl *Def = Proto->getDefinition())
|
2020-06-08 21:37:44 +08:00
|
|
|
if (!Def->isUnconditionallyVisible() && !AllowHidden)
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2013-01-17 08:38:46 +08:00
|
|
|
}
|
|
|
|
|
2009-02-23 03:35:57 +08:00
|
|
|
// Since instance & class methods can have the same name, the loop below
|
|
|
|
// ensures we get the correct method.
|
|
|
|
//
|
|
|
|
// @interface Whatever
|
|
|
|
// - (int) class_method;
|
|
|
|
// + (float) class_method;
|
|
|
|
// @end
|
2015-02-21 10:45:19 +08:00
|
|
|
lookup_result R = lookup(Sel);
|
|
|
|
for (lookup_iterator Meth = R.begin(), MethEnd = R.end();
|
2012-12-19 08:45:41 +08:00
|
|
|
Meth != MethEnd; ++Meth) {
|
2018-04-10 06:14:10 +08:00
|
|
|
auto *MD = dyn_cast<ObjCMethodDecl>(*Meth);
|
2009-07-26 06:15:22 +08:00
|
|
|
if (MD && MD->isInstanceMethod() == isInstance)
|
2009-02-23 03:35:57 +08:00
|
|
|
return MD;
|
|
|
|
}
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2009-02-21 04:59:54 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// This routine returns 'true' if a user declared setter method was
|
2014-12-22 13:21:03 +08:00
|
|
|
/// found in the class, its protocols, its super classes or categories.
|
|
|
|
/// It also returns 'true' if one of its categories has declared a 'readwrite'
|
|
|
|
/// property. This is because, user must provide a setter method for the
|
|
|
|
/// category's 'readwrite' property.
|
|
|
|
bool ObjCContainerDecl::HasUserDeclaredSetterMethod(
|
|
|
|
const ObjCPropertyDecl *Property) const {
|
2013-03-22 04:50:53 +08:00
|
|
|
Selector Sel = Property->getSetterName();
|
2015-02-21 10:45:19 +08:00
|
|
|
lookup_result R = lookup(Sel);
|
|
|
|
for (lookup_iterator Meth = R.begin(), MethEnd = R.end();
|
2013-03-22 04:50:53 +08:00
|
|
|
Meth != MethEnd; ++Meth) {
|
2018-04-10 06:14:10 +08:00
|
|
|
auto *MD = dyn_cast<ObjCMethodDecl>(*Meth);
|
2013-03-22 04:50:53 +08:00
|
|
|
if (MD && MD->isInstanceMethod() && !MD->isImplicit())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-04-10 06:14:10 +08:00
|
|
|
if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(this)) {
|
2013-03-22 04:50:53 +08:00
|
|
|
// Also look into categories, including class extensions, looking
|
|
|
|
// for a user declared instance method.
|
2014-03-14 05:23:55 +08:00
|
|
|
for (const auto *Cat : ID->visible_categories()) {
|
2013-03-22 04:50:53 +08:00
|
|
|
if (ObjCMethodDecl *MD = Cat->getInstanceMethod(Sel))
|
|
|
|
if (!MD->isImplicit())
|
|
|
|
return true;
|
|
|
|
if (Cat->IsClassExtension())
|
|
|
|
continue;
|
2014-12-22 13:21:03 +08:00
|
|
|
// Also search through the categories looking for a 'readwrite'
|
|
|
|
// declaration of this property. If one found, presumably a setter will
|
|
|
|
// be provided (properties declared in categories will not get
|
|
|
|
// auto-synthesized).
|
2016-01-28 04:00:32 +08:00
|
|
|
for (const auto *P : Cat->properties())
|
2013-03-22 04:50:53 +08:00
|
|
|
if (P->getIdentifier() == Property->getIdentifier()) {
|
2020-04-23 14:20:56 +08:00
|
|
|
if (P->getPropertyAttributes() &
|
|
|
|
ObjCPropertyAttribute::kind_readwrite)
|
2013-03-22 04:50:53 +08:00
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-03-22 04:50:53 +08:00
|
|
|
// Also look into protocols, for a user declared instance method.
|
2014-03-14 04:55:22 +08:00
|
|
|
for (const auto *Proto : ID->all_referenced_protocols())
|
2013-03-22 04:50:53 +08:00
|
|
|
if (Proto->HasUserDeclaredSetterMethod(Property))
|
|
|
|
return true;
|
2014-03-14 04:55:22 +08:00
|
|
|
|
2013-03-22 04:50:53 +08:00
|
|
|
// And in its super class.
|
|
|
|
ObjCInterfaceDecl *OSC = ID->getSuperClass();
|
|
|
|
while (OSC) {
|
|
|
|
if (OSC->HasUserDeclaredSetterMethod(Property))
|
|
|
|
return true;
|
|
|
|
OSC = OSC->getSuperClass();
|
|
|
|
}
|
|
|
|
}
|
2018-04-10 06:14:10 +08:00
|
|
|
if (const auto *PD = dyn_cast<ObjCProtocolDecl>(this))
|
2014-03-14 06:58:06 +08:00
|
|
|
for (const auto *PI : PD->protocols())
|
|
|
|
if (PI->HasUserDeclaredSetterMethod(Property))
|
2013-03-22 04:50:53 +08:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-03-16 04:11:46 +08:00
|
|
|
ObjCPropertyDecl *
|
2010-03-16 04:11:53 +08:00
|
|
|
ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC,
|
2016-01-29 02:49:28 +08:00
|
|
|
const IdentifierInfo *propertyID,
|
|
|
|
ObjCPropertyQueryKind queryKind) {
|
2013-01-17 08:38:46 +08:00
|
|
|
// If this context is a hidden protocol definition, don't find any
|
|
|
|
// property.
|
2018-04-10 06:14:10 +08:00
|
|
|
if (const auto *Proto = dyn_cast<ObjCProtocolDecl>(DC)) {
|
2013-01-17 08:38:46 +08:00
|
|
|
if (const ObjCProtocolDecl *Def = Proto->getDefinition())
|
2020-06-08 21:37:44 +08:00
|
|
|
if (!Def->isUnconditionallyVisible())
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2013-01-17 08:38:46 +08:00
|
|
|
}
|
2010-03-16 04:11:46 +08:00
|
|
|
|
2017-02-23 07:18:49 +08:00
|
|
|
// If context is class, then lookup property in its visible extensions.
|
Stop back-patching 'readonly' Objective-C properties with 'readwrite' ones.
A 'readonly' Objective-C property declared in the primary class can
effectively be shadowed by a 'readwrite' property declared within an
extension of that class, so long as the types and attributes of the
two property declarations are compatible.
Previously, this functionality was implemented by back-patching the
original 'readonly' property to make it 'readwrite', destroying source
information and causing some hideously redundant, incorrect
code. Simplify the implementation to express how this should actually
be modeled: as a separate property declaration in the extension that
shadows (via the name lookup rules) the declaration in the primary
class. While here, correct some broken Fix-Its, eliminate a pile of
redundant code, clean up the ARC migrator's handling of properties
declared in extensions, and fix debug info's naming of methods that
come from categories.
A wonderous side effect of doing this write is that it eliminates the
"AddedObjCPropertyInClassExtension" method from the AST mutation
listener, which in turn eliminates the last place where we rewrite
entire declarations in a chained PCH file or a module file. This
change (which fixes rdar://problem/18475765) will allow us to
eliminate the rewritten-decls logic from the serialization library,
and fixes a crash (rdar://problem/23247794) illustrated by the
test/PCH/chain-categories.m example.
llvm-svn: 251874
2015-11-03 09:15:46 +08:00
|
|
|
// This comes before property is looked up in primary class.
|
|
|
|
if (auto *IDecl = dyn_cast<ObjCInterfaceDecl>(DC)) {
|
2017-02-23 07:18:49 +08:00
|
|
|
for (const auto *Ext : IDecl->visible_extensions())
|
Stop back-patching 'readonly' Objective-C properties with 'readwrite' ones.
A 'readonly' Objective-C property declared in the primary class can
effectively be shadowed by a 'readwrite' property declared within an
extension of that class, so long as the types and attributes of the
two property declarations are compatible.
Previously, this functionality was implemented by back-patching the
original 'readonly' property to make it 'readwrite', destroying source
information and causing some hideously redundant, incorrect
code. Simplify the implementation to express how this should actually
be modeled: as a separate property declaration in the extension that
shadows (via the name lookup rules) the declaration in the primary
class. While here, correct some broken Fix-Its, eliminate a pile of
redundant code, clean up the ARC migrator's handling of properties
declared in extensions, and fix debug info's naming of methods that
come from categories.
A wonderous side effect of doing this write is that it eliminates the
"AddedObjCPropertyInClassExtension" method from the AST mutation
listener, which in turn eliminates the last place where we rewrite
entire declarations in a chained PCH file or a module file. This
change (which fixes rdar://problem/18475765) will allow us to
eliminate the rewritten-decls logic from the serialization library,
and fixes a crash (rdar://problem/23247794) illustrated by the
test/PCH/chain-categories.m example.
llvm-svn: 251874
2015-11-03 09:15:46 +08:00
|
|
|
if (ObjCPropertyDecl *PD = ObjCPropertyDecl::findPropertyDecl(Ext,
|
2016-01-29 02:49:28 +08:00
|
|
|
propertyID,
|
|
|
|
queryKind))
|
Stop back-patching 'readonly' Objective-C properties with 'readwrite' ones.
A 'readonly' Objective-C property declared in the primary class can
effectively be shadowed by a 'readwrite' property declared within an
extension of that class, so long as the types and attributes of the
two property declarations are compatible.
Previously, this functionality was implemented by back-patching the
original 'readonly' property to make it 'readwrite', destroying source
information and causing some hideously redundant, incorrect
code. Simplify the implementation to express how this should actually
be modeled: as a separate property declaration in the extension that
shadows (via the name lookup rules) the declaration in the primary
class. While here, correct some broken Fix-Its, eliminate a pile of
redundant code, clean up the ARC migrator's handling of properties
declared in extensions, and fix debug info's naming of methods that
come from categories.
A wonderous side effect of doing this write is that it eliminates the
"AddedObjCPropertyInClassExtension" method from the AST mutation
listener, which in turn eliminates the last place where we rewrite
entire declarations in a chained PCH file or a module file. This
change (which fixes rdar://problem/18475765) will allow us to
eliminate the rewritten-decls logic from the serialization library,
and fixes a crash (rdar://problem/23247794) illustrated by the
test/PCH/chain-categories.m example.
llvm-svn: 251874
2015-11-03 09:15:46 +08:00
|
|
|
return PD;
|
|
|
|
}
|
|
|
|
|
2015-02-21 10:45:19 +08:00
|
|
|
DeclContext::lookup_result R = DC->lookup(propertyID);
|
2016-01-29 02:49:28 +08:00
|
|
|
ObjCPropertyDecl *classProp = nullptr;
|
2015-02-21 10:45:19 +08:00
|
|
|
for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
|
2012-12-19 08:45:41 +08:00
|
|
|
++I)
|
2018-04-10 06:14:10 +08:00
|
|
|
if (auto *PD = dyn_cast<ObjCPropertyDecl>(*I)) {
|
2016-01-29 02:49:28 +08:00
|
|
|
// If queryKind is unknown, we return the instance property if one
|
|
|
|
// exists; otherwise we return the class property.
|
|
|
|
if ((queryKind == ObjCPropertyQueryKind::OBJC_PR_query_unknown &&
|
|
|
|
!PD->isClassProperty()) ||
|
|
|
|
(queryKind == ObjCPropertyQueryKind::OBJC_PR_query_class &&
|
|
|
|
PD->isClassProperty()) ||
|
|
|
|
(queryKind == ObjCPropertyQueryKind::OBJC_PR_query_instance &&
|
|
|
|
!PD->isClassProperty()))
|
|
|
|
return PD;
|
|
|
|
|
|
|
|
if (PD->isClassProperty())
|
|
|
|
classProp = PD;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (queryKind == ObjCPropertyQueryKind::OBJC_PR_query_unknown)
|
|
|
|
// We can't find the instance property, return the class property.
|
|
|
|
return classProp;
|
2010-03-16 04:11:46 +08:00
|
|
|
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2010-03-16 04:11:46 +08:00
|
|
|
}
|
|
|
|
|
2012-09-28 03:45:11 +08:00
|
|
|
IdentifierInfo *
|
|
|
|
ObjCPropertyDecl::getDefaultSynthIvarName(ASTContext &Ctx) const {
|
|
|
|
SmallString<128> ivarName;
|
|
|
|
{
|
|
|
|
llvm::raw_svector_ostream os(ivarName);
|
|
|
|
os << '_' << getIdentifier()->getName();
|
|
|
|
}
|
|
|
|
return &Ctx.Idents.get(ivarName.str());
|
|
|
|
}
|
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
/// FindPropertyDeclaration - Finds declaration of the property given its name
|
|
|
|
/// in 'PropertyId' and returns it. It returns 0, if not found.
|
2014-11-20 06:03:46 +08:00
|
|
|
ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration(
|
2016-01-29 02:49:28 +08:00
|
|
|
const IdentifierInfo *PropertyId,
|
|
|
|
ObjCPropertyQueryKind QueryKind) const {
|
2013-01-17 08:38:46 +08:00
|
|
|
// Don't find properties within hidden protocol definitions.
|
2018-04-10 06:14:10 +08:00
|
|
|
if (const auto *Proto = dyn_cast<ObjCProtocolDecl>(this)) {
|
2013-01-17 08:38:46 +08:00
|
|
|
if (const ObjCProtocolDecl *Def = Proto->getDefinition())
|
2020-06-08 21:37:44 +08:00
|
|
|
if (!Def->isUnconditionallyVisible())
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2013-01-17 08:38:46 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
Stop back-patching 'readonly' Objective-C properties with 'readwrite' ones.
A 'readonly' Objective-C property declared in the primary class can
effectively be shadowed by a 'readwrite' property declared within an
extension of that class, so long as the types and attributes of the
two property declarations are compatible.
Previously, this functionality was implemented by back-patching the
original 'readonly' property to make it 'readwrite', destroying source
information and causing some hideously redundant, incorrect
code. Simplify the implementation to express how this should actually
be modeled: as a separate property declaration in the extension that
shadows (via the name lookup rules) the declaration in the primary
class. While here, correct some broken Fix-Its, eliminate a pile of
redundant code, clean up the ARC migrator's handling of properties
declared in extensions, and fix debug info's naming of methods that
come from categories.
A wonderous side effect of doing this write is that it eliminates the
"AddedObjCPropertyInClassExtension" method from the AST mutation
listener, which in turn eliminates the last place where we rewrite
entire declarations in a chained PCH file or a module file. This
change (which fixes rdar://problem/18475765) will allow us to
eliminate the rewritten-decls logic from the serialization library,
and fixes a crash (rdar://problem/23247794) illustrated by the
test/PCH/chain-categories.m example.
llvm-svn: 251874
2015-11-03 09:15:46 +08:00
|
|
|
// Search the extensions of a class first; they override what's in
|
|
|
|
// the class itself.
|
|
|
|
if (const auto *ClassDecl = dyn_cast<ObjCInterfaceDecl>(this)) {
|
|
|
|
for (const auto *Ext : ClassDecl->visible_extensions()) {
|
2016-01-29 02:49:28 +08:00
|
|
|
if (auto *P = Ext->FindPropertyDeclaration(PropertyId, QueryKind))
|
Stop back-patching 'readonly' Objective-C properties with 'readwrite' ones.
A 'readonly' Objective-C property declared in the primary class can
effectively be shadowed by a 'readwrite' property declared within an
extension of that class, so long as the types and attributes of the
two property declarations are compatible.
Previously, this functionality was implemented by back-patching the
original 'readonly' property to make it 'readwrite', destroying source
information and causing some hideously redundant, incorrect
code. Simplify the implementation to express how this should actually
be modeled: as a separate property declaration in the extension that
shadows (via the name lookup rules) the declaration in the primary
class. While here, correct some broken Fix-Its, eliminate a pile of
redundant code, clean up the ARC migrator's handling of properties
declared in extensions, and fix debug info's naming of methods that
come from categories.
A wonderous side effect of doing this write is that it eliminates the
"AddedObjCPropertyInClassExtension" method from the AST mutation
listener, which in turn eliminates the last place where we rewrite
entire declarations in a chained PCH file or a module file. This
change (which fixes rdar://problem/18475765) will allow us to
eliminate the rewritten-decls logic from the serialization library,
and fixes a crash (rdar://problem/23247794) illustrated by the
test/PCH/chain-categories.m example.
llvm-svn: 251874
2015-11-03 09:15:46 +08:00
|
|
|
return P;
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-03-16 04:11:53 +08:00
|
|
|
if (ObjCPropertyDecl *PD =
|
2016-01-29 02:49:28 +08:00
|
|
|
ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId,
|
|
|
|
QueryKind))
|
2010-03-16 04:11:53 +08:00
|
|
|
return PD;
|
|
|
|
|
|
|
|
switch (getKind()) {
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
case Decl::ObjCProtocol: {
|
2018-04-10 06:14:10 +08:00
|
|
|
const auto *PID = cast<ObjCProtocolDecl>(this);
|
2014-03-14 06:58:06 +08:00
|
|
|
for (const auto *I : PID->protocols())
|
2016-01-29 02:49:28 +08:00
|
|
|
if (ObjCPropertyDecl *P = I->FindPropertyDeclaration(PropertyId,
|
|
|
|
QueryKind))
|
2010-02-16 05:55:26 +08:00
|
|
|
return P;
|
2010-03-16 04:11:53 +08:00
|
|
|
break;
|
2009-02-21 04:59:54 +08:00
|
|
|
}
|
2010-03-16 04:11:53 +08:00
|
|
|
case Decl::ObjCInterface: {
|
2018-04-10 06:14:10 +08:00
|
|
|
const auto *OID = cast<ObjCInterfaceDecl>(this);
|
Stop back-patching 'readonly' Objective-C properties with 'readwrite' ones.
A 'readonly' Objective-C property declared in the primary class can
effectively be shadowed by a 'readwrite' property declared within an
extension of that class, so long as the types and attributes of the
two property declarations are compatible.
Previously, this functionality was implemented by back-patching the
original 'readonly' property to make it 'readwrite', destroying source
information and causing some hideously redundant, incorrect
code. Simplify the implementation to express how this should actually
be modeled: as a separate property declaration in the extension that
shadows (via the name lookup rules) the declaration in the primary
class. While here, correct some broken Fix-Its, eliminate a pile of
redundant code, clean up the ARC migrator's handling of properties
declared in extensions, and fix debug info's naming of methods that
come from categories.
A wonderous side effect of doing this write is that it eliminates the
"AddedObjCPropertyInClassExtension" method from the AST mutation
listener, which in turn eliminates the last place where we rewrite
entire declarations in a chained PCH file or a module file. This
change (which fixes rdar://problem/18475765) will allow us to
eliminate the rewritten-decls logic from the serialization library,
and fixes a crash (rdar://problem/23247794) illustrated by the
test/PCH/chain-categories.m example.
llvm-svn: 251874
2015-11-03 09:15:46 +08:00
|
|
|
// Look through categories (but not extensions; they were handled above).
|
2014-03-14 05:23:55 +08:00
|
|
|
for (const auto *Cat : OID->visible_categories()) {
|
2010-03-16 04:11:53 +08:00
|
|
|
if (!Cat->IsClassExtension())
|
2016-01-29 02:49:28 +08:00
|
|
|
if (ObjCPropertyDecl *P = Cat->FindPropertyDeclaration(
|
|
|
|
PropertyId, QueryKind))
|
2010-03-16 04:11:53 +08:00
|
|
|
return P;
|
2013-01-17 07:00:23 +08:00
|
|
|
}
|
2010-03-16 04:11:53 +08:00
|
|
|
|
|
|
|
// Look through protocols.
|
2014-03-14 04:55:22 +08:00
|
|
|
for (const auto *I : OID->all_referenced_protocols())
|
2016-01-29 02:49:28 +08:00
|
|
|
if (ObjCPropertyDecl *P = I->FindPropertyDeclaration(PropertyId,
|
|
|
|
QueryKind))
|
2010-03-16 04:11:53 +08:00
|
|
|
return P;
|
|
|
|
|
|
|
|
// Finally, check the super class.
|
|
|
|
if (const ObjCInterfaceDecl *superClass = OID->getSuperClass())
|
2016-01-29 02:49:28 +08:00
|
|
|
return superClass->FindPropertyDeclaration(PropertyId, QueryKind);
|
2010-03-16 04:11:53 +08:00
|
|
|
break;
|
2009-02-21 04:59:54 +08:00
|
|
|
}
|
2010-03-16 04:11:53 +08:00
|
|
|
case Decl::ObjCCategory: {
|
2018-04-10 06:14:10 +08:00
|
|
|
const auto *OCD = cast<ObjCCategoryDecl>(this);
|
2010-03-16 04:11:53 +08:00
|
|
|
// Look through protocols.
|
|
|
|
if (!OCD->IsClassExtension())
|
2014-03-14 20:55:57 +08:00
|
|
|
for (const auto *I : OCD->protocols())
|
2016-01-29 02:49:28 +08:00
|
|
|
if (ObjCPropertyDecl *P = I->FindPropertyDeclaration(PropertyId,
|
|
|
|
QueryKind))
|
2014-03-14 20:55:57 +08:00
|
|
|
return P;
|
2010-03-16 04:11:53 +08:00
|
|
|
break;
|
2009-02-21 04:59:54 +08:00
|
|
|
}
|
|
|
|
}
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2009-02-21 04:59:54 +08:00
|
|
|
}
|
|
|
|
|
2017-11-23 05:32:07 +08:00
|
|
|
void ObjCInterfaceDecl::anchor() {}
|
2011-12-20 10:48:34 +08:00
|
|
|
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
ObjCTypeParamList *ObjCInterfaceDecl::getTypeParamList() const {
|
|
|
|
// If this particular declaration has a type parameter list, return it.
|
|
|
|
if (ObjCTypeParamList *written = getTypeParamListAsWritten())
|
|
|
|
return written;
|
|
|
|
|
|
|
|
// If there is a definition, return its type parameter list.
|
|
|
|
if (const ObjCInterfaceDecl *def = getDefinition())
|
|
|
|
return def->getTypeParamListAsWritten();
|
|
|
|
|
|
|
|
// Otherwise, look at previous declarations to determine whether any
|
|
|
|
// of them has a type parameter list, skipping over those
|
|
|
|
// declarations that do not.
|
2018-04-10 06:14:10 +08:00
|
|
|
for (const ObjCInterfaceDecl *decl = getMostRecentDecl(); decl;
|
|
|
|
decl = decl->getPreviousDecl()) {
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
if (ObjCTypeParamList *written = decl->getTypeParamListAsWritten())
|
|
|
|
return written;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-07-07 14:20:12 +08:00
|
|
|
void ObjCInterfaceDecl::setTypeParamList(ObjCTypeParamList *TPL) {
|
|
|
|
TypeParamList = TPL;
|
|
|
|
if (!TPL)
|
|
|
|
return;
|
|
|
|
// Set the declaration context of each of the type parameters.
|
2018-04-10 06:14:10 +08:00
|
|
|
for (auto *typeParam : *TypeParamList)
|
2015-07-07 14:20:12 +08:00
|
|
|
typeParam->setDeclContext(this);
|
|
|
|
}
|
|
|
|
|
2015-07-07 11:57:35 +08:00
|
|
|
ObjCInterfaceDecl *ObjCInterfaceDecl::getSuperClass() const {
|
|
|
|
// FIXME: Should make sure no callers ever do this.
|
|
|
|
if (!hasDefinition())
|
|
|
|
return nullptr;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2015-07-07 11:57:35 +08:00
|
|
|
if (data().ExternallyCompleted)
|
|
|
|
LoadExternalDefinition();
|
|
|
|
|
|
|
|
if (const ObjCObjectType *superType = getSuperClassType()) {
|
|
|
|
if (ObjCInterfaceDecl *superDecl = superType->getInterface()) {
|
|
|
|
if (ObjCInterfaceDecl *superDef = superDecl->getDefinition())
|
|
|
|
return superDef;
|
|
|
|
|
|
|
|
return superDecl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation ObjCInterfaceDecl::getSuperClassLoc() const {
|
|
|
|
if (TypeSourceInfo *superTInfo = getSuperClassTInfo())
|
2018-08-10 05:08:08 +08:00
|
|
|
return superTInfo->getTypeLoc().getBeginLoc();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2015-07-07 11:57:35 +08:00
|
|
|
return SourceLocation();
|
|
|
|
}
|
|
|
|
|
2009-11-03 06:45:15 +08:00
|
|
|
/// FindPropertyVisibleInPrimaryClass - Finds declaration of the property
|
|
|
|
/// with name 'PropertyId' in the primary class; including those in protocols
|
2010-03-16 04:30:07 +08:00
|
|
|
/// (direct or indirect) used by the primary class.
|
2009-11-03 06:45:15 +08:00
|
|
|
ObjCPropertyDecl *
|
2010-03-16 04:30:07 +08:00
|
|
|
ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
|
2016-01-29 02:49:28 +08:00
|
|
|
IdentifierInfo *PropertyId,
|
|
|
|
ObjCPropertyQueryKind QueryKind) const {
|
2011-12-15 13:27:12 +08:00
|
|
|
// FIXME: Should make sure no callers ever do this.
|
|
|
|
if (!hasDefinition())
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
|
|
|
|
2011-12-15 13:27:12 +08:00
|
|
|
if (data().ExternallyCompleted)
|
2010-12-02 07:49:52 +08:00
|
|
|
LoadExternalDefinition();
|
|
|
|
|
2010-03-16 04:30:07 +08:00
|
|
|
if (ObjCPropertyDecl *PD =
|
2016-01-29 02:49:28 +08:00
|
|
|
ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId,
|
|
|
|
QueryKind))
|
2010-03-16 04:30:07 +08:00
|
|
|
return PD;
|
|
|
|
|
2009-11-03 06:45:15 +08:00
|
|
|
// Look through protocols.
|
2014-03-14 04:55:22 +08:00
|
|
|
for (const auto *I : all_referenced_protocols())
|
2016-01-29 02:49:28 +08:00
|
|
|
if (ObjCPropertyDecl *P = I->FindPropertyDeclaration(PropertyId,
|
|
|
|
QueryKind))
|
2009-11-03 06:45:15 +08:00
|
|
|
return P;
|
2010-03-16 04:30:07 +08:00
|
|
|
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2009-11-03 06:45:15 +08:00
|
|
|
}
|
|
|
|
|
2013-02-15 06:33:34 +08:00
|
|
|
void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM,
|
|
|
|
PropertyDeclOrder &PO) const {
|
2016-01-29 07:36:05 +08:00
|
|
|
for (auto *Prop : properties()) {
|
|
|
|
PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;
|
2013-02-15 06:33:34 +08:00
|
|
|
PO.push_back(Prop);
|
2012-10-19 03:17:53 +08:00
|
|
|
}
|
Stop back-patching 'readonly' Objective-C properties with 'readwrite' ones.
A 'readonly' Objective-C property declared in the primary class can
effectively be shadowed by a 'readwrite' property declared within an
extension of that class, so long as the types and attributes of the
two property declarations are compatible.
Previously, this functionality was implemented by back-patching the
original 'readonly' property to make it 'readwrite', destroying source
information and causing some hideously redundant, incorrect
code. Simplify the implementation to express how this should actually
be modeled: as a separate property declaration in the extension that
shadows (via the name lookup rules) the declaration in the primary
class. While here, correct some broken Fix-Its, eliminate a pile of
redundant code, clean up the ARC migrator's handling of properties
declared in extensions, and fix debug info's naming of methods that
come from categories.
A wonderous side effect of doing this write is that it eliminates the
"AddedObjCPropertyInClassExtension" method from the AST mutation
listener, which in turn eliminates the last place where we rewrite
entire declarations in a chained PCH file or a module file. This
change (which fixes rdar://problem/18475765) will allow us to
eliminate the rewritten-decls logic from the serialization library,
and fixes a crash (rdar://problem/23247794) illustrated by the
test/PCH/chain-categories.m example.
llvm-svn: 251874
2015-11-03 09:15:46 +08:00
|
|
|
for (const auto *Ext : known_extensions()) {
|
|
|
|
const ObjCCategoryDecl *ClassExt = Ext;
|
2016-01-29 07:36:05 +08:00
|
|
|
for (auto *Prop : ClassExt->properties()) {
|
|
|
|
PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;
|
Stop back-patching 'readonly' Objective-C properties with 'readwrite' ones.
A 'readonly' Objective-C property declared in the primary class can
effectively be shadowed by a 'readwrite' property declared within an
extension of that class, so long as the types and attributes of the
two property declarations are compatible.
Previously, this functionality was implemented by back-patching the
original 'readonly' property to make it 'readwrite', destroying source
information and causing some hideously redundant, incorrect
code. Simplify the implementation to express how this should actually
be modeled: as a separate property declaration in the extension that
shadows (via the name lookup rules) the declaration in the primary
class. While here, correct some broken Fix-Its, eliminate a pile of
redundant code, clean up the ARC migrator's handling of properties
declared in extensions, and fix debug info's naming of methods that
come from categories.
A wonderous side effect of doing this write is that it eliminates the
"AddedObjCPropertyInClassExtension" method from the AST mutation
listener, which in turn eliminates the last place where we rewrite
entire declarations in a chained PCH file or a module file. This
change (which fixes rdar://problem/18475765) will allow us to
eliminate the rewritten-decls logic from the serialization library,
and fixes a crash (rdar://problem/23247794) illustrated by the
test/PCH/chain-categories.m example.
llvm-svn: 251874
2015-11-03 09:15:46 +08:00
|
|
|
PO.push_back(Prop);
|
|
|
|
}
|
|
|
|
}
|
2014-03-14 04:55:22 +08:00
|
|
|
for (const auto *PI : all_referenced_protocols())
|
|
|
|
PI->collectPropertiesToImplement(PM, PO);
|
2012-10-31 09:18:22 +08:00
|
|
|
// Note, the properties declared only in class extensions are still copied
|
|
|
|
// into the main @interface's property list, and therefore we don't
|
|
|
|
// explicitly, have to search class extension properties.
|
2012-10-19 03:17:53 +08:00
|
|
|
}
|
|
|
|
|
2012-12-01 23:09:41 +08:00
|
|
|
bool ObjCInterfaceDecl::isArcWeakrefUnavailable() const {
|
|
|
|
const ObjCInterfaceDecl *Class = this;
|
|
|
|
while (Class) {
|
|
|
|
if (Class->hasAttr<ArcWeakrefUnavailableAttr>())
|
|
|
|
return true;
|
|
|
|
Class = Class->getSuperClass();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ObjCInterfaceDecl *ObjCInterfaceDecl::isObjCRequiresPropertyDefs() const {
|
|
|
|
const ObjCInterfaceDecl *Class = this;
|
|
|
|
while (Class) {
|
|
|
|
if (Class->hasAttr<ObjCRequiresPropertyDefsAttr>())
|
|
|
|
return Class;
|
|
|
|
Class = Class->getSuperClass();
|
|
|
|
}
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2012-12-01 23:09:41 +08:00
|
|
|
}
|
|
|
|
|
2009-10-06 04:41:32 +08:00
|
|
|
void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
|
|
|
|
ObjCProtocolDecl *const* ExtList, unsigned ExtNum,
|
2017-11-23 05:32:07 +08:00
|
|
|
ASTContext &C) {
|
2011-12-15 13:27:12 +08:00
|
|
|
if (data().ExternallyCompleted)
|
2010-12-02 07:49:52 +08:00
|
|
|
LoadExternalDefinition();
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
if (data().AllReferencedProtocols.empty() &&
|
2011-12-15 13:27:12 +08:00
|
|
|
data().ReferencedProtocols.empty()) {
|
|
|
|
data().AllReferencedProtocols.set(ExtList, ExtNum, C);
|
2009-10-06 04:41:32 +08:00
|
|
|
return;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-10-06 04:41:32 +08:00
|
|
|
// Check for duplicate protocol in class's protocol list.
|
2010-09-01 09:21:15 +08:00
|
|
|
// This is O(n*m). But it is extremely rare and number of protocols in
|
2009-10-06 04:41:32 +08:00
|
|
|
// class or its extension are very few.
|
2018-04-10 06:14:10 +08:00
|
|
|
SmallVector<ObjCProtocolDecl *, 8> ProtocolRefs;
|
2009-10-06 04:41:32 +08:00
|
|
|
for (unsigned i = 0; i < ExtNum; i++) {
|
|
|
|
bool protocolExists = false;
|
|
|
|
ObjCProtocolDecl *ProtoInExtension = ExtList[i];
|
2014-03-14 04:55:22 +08:00
|
|
|
for (auto *Proto : all_referenced_protocols()) {
|
2009-10-06 04:41:32 +08:00
|
|
|
if (C.ProtocolCompatibleWithProtocol(ProtoInExtension, Proto)) {
|
|
|
|
protocolExists = true;
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
}
|
2009-10-06 04:41:32 +08:00
|
|
|
}
|
|
|
|
// Do we want to warn on a protocol in extension class which
|
|
|
|
// already exist in the class? Probably not.
|
2010-09-01 09:21:15 +08:00
|
|
|
if (!protocolExists)
|
2009-10-06 04:41:32 +08:00
|
|
|
ProtocolRefs.push_back(ProtoInExtension);
|
|
|
|
}
|
2010-09-01 09:21:15 +08:00
|
|
|
|
2009-10-06 04:41:32 +08:00
|
|
|
if (ProtocolRefs.empty())
|
|
|
|
return;
|
2010-09-01 09:21:15 +08:00
|
|
|
|
2009-10-06 05:32:49 +08:00
|
|
|
// Merge ProtocolRefs into class's protocol list;
|
2015-02-18 00:48:30 +08:00
|
|
|
ProtocolRefs.append(all_referenced_protocol_begin(),
|
|
|
|
all_referenced_protocol_end());
|
2010-09-01 09:21:15 +08:00
|
|
|
|
2011-12-15 13:27:12 +08:00
|
|
|
data().AllReferencedProtocols.set(ProtocolRefs.data(), ProtocolRefs.size(),C);
|
2009-10-06 04:41:32 +08:00
|
|
|
}
|
|
|
|
|
2013-12-05 15:07:03 +08:00
|
|
|
const ObjCInterfaceDecl *
|
|
|
|
ObjCInterfaceDecl::findInterfaceWithDesignatedInitializers() const {
|
2013-12-04 05:11:30 +08:00
|
|
|
const ObjCInterfaceDecl *IFace = this;
|
|
|
|
while (IFace) {
|
2013-12-05 15:07:03 +08:00
|
|
|
if (IFace->hasDesignatedInitializers())
|
|
|
|
return IFace;
|
|
|
|
if (!IFace->inheritsDesignatedInitializers())
|
2013-12-04 05:11:30 +08:00
|
|
|
break;
|
|
|
|
IFace = IFace->getSuperClass();
|
|
|
|
}
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2013-12-05 15:07:03 +08:00
|
|
|
}
|
|
|
|
|
2014-03-29 06:45:38 +08:00
|
|
|
static bool isIntroducingInitializers(const ObjCInterfaceDecl *D) {
|
|
|
|
for (const auto *MD : D->instance_methods()) {
|
|
|
|
if (MD->getMethodFamily() == OMF_init && !MD->isOverriding())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
for (const auto *Ext : D->visible_extensions()) {
|
|
|
|
for (const auto *MD : Ext->instance_methods()) {
|
|
|
|
if (MD->getMethodFamily() == OMF_init && !MD->isOverriding())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2014-04-17 02:32:42 +08:00
|
|
|
if (const auto *ImplD = D->getImplementation()) {
|
2014-04-17 02:45:32 +08:00
|
|
|
for (const auto *MD : ImplD->instance_methods()) {
|
|
|
|
if (MD->getMethodFamily() == OMF_init && !MD->isOverriding())
|
|
|
|
return true;
|
|
|
|
}
|
2014-04-17 02:32:42 +08:00
|
|
|
}
|
2014-03-29 06:45:38 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-12-05 15:07:03 +08:00
|
|
|
bool ObjCInterfaceDecl::inheritsDesignatedInitializers() const {
|
|
|
|
switch (data().InheritedDesignatedInitializers) {
|
|
|
|
case DefinitionData::IDI_Inherited:
|
|
|
|
return true;
|
|
|
|
case DefinitionData::IDI_NotInherited:
|
|
|
|
return false;
|
2017-11-23 05:32:07 +08:00
|
|
|
case DefinitionData::IDI_Unknown:
|
2013-12-05 15:07:03 +08:00
|
|
|
// If the class introduced initializers we conservatively assume that we
|
|
|
|
// don't know if any of them is a designated initializer to avoid possible
|
|
|
|
// misleading warnings.
|
2014-03-29 06:45:38 +08:00
|
|
|
if (isIntroducingInitializers(this)) {
|
2013-12-05 15:07:03 +08:00
|
|
|
data().InheritedDesignatedInitializers = DefinitionData::IDI_NotInherited;
|
|
|
|
} else {
|
2014-04-27 05:28:41 +08:00
|
|
|
if (auto SuperD = getSuperClass()) {
|
|
|
|
data().InheritedDesignatedInitializers =
|
|
|
|
SuperD->declaresOrInheritsDesignatedInitializers() ?
|
|
|
|
DefinitionData::IDI_Inherited :
|
|
|
|
DefinitionData::IDI_NotInherited;
|
|
|
|
} else {
|
|
|
|
data().InheritedDesignatedInitializers =
|
|
|
|
DefinitionData::IDI_NotInherited;
|
|
|
|
}
|
2013-12-05 15:07:03 +08:00
|
|
|
}
|
2014-04-27 05:28:41 +08:00
|
|
|
assert(data().InheritedDesignatedInitializers
|
|
|
|
!= DefinitionData::IDI_Unknown);
|
|
|
|
return data().InheritedDesignatedInitializers ==
|
|
|
|
DefinitionData::IDI_Inherited;
|
2013-12-05 15:07:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
llvm_unreachable("unexpected InheritedDesignatedInitializers value");
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObjCInterfaceDecl::getDesignatedInitializers(
|
|
|
|
llvm::SmallVectorImpl<const ObjCMethodDecl *> &Methods) const {
|
2014-03-12 02:56:18 +08:00
|
|
|
// Check for a complete definition and recover if not so.
|
|
|
|
if (!isThisDeclarationADefinition())
|
|
|
|
return;
|
2013-12-05 15:07:03 +08:00
|
|
|
if (data().ExternallyCompleted)
|
|
|
|
LoadExternalDefinition();
|
2013-12-04 05:11:30 +08:00
|
|
|
|
2013-12-05 15:07:03 +08:00
|
|
|
const ObjCInterfaceDecl *IFace= findInterfaceWithDesignatedInitializers();
|
2013-12-04 05:11:30 +08:00
|
|
|
if (!IFace)
|
|
|
|
return;
|
2013-12-05 15:07:03 +08:00
|
|
|
|
2014-03-14 03:50:17 +08:00
|
|
|
for (const auto *MD : IFace->instance_methods())
|
2013-12-04 05:11:36 +08:00
|
|
|
if (MD->isThisDeclarationADesignatedInitializer())
|
2013-12-04 05:11:30 +08:00
|
|
|
Methods.push_back(MD);
|
2014-03-29 06:45:38 +08:00
|
|
|
for (const auto *Ext : IFace->visible_extensions()) {
|
|
|
|
for (const auto *MD : Ext->instance_methods())
|
|
|
|
if (MD->isThisDeclarationADesignatedInitializer())
|
|
|
|
Methods.push_back(MD);
|
|
|
|
}
|
2013-12-04 05:11:30 +08:00
|
|
|
}
|
|
|
|
|
2013-12-04 05:11:36 +08:00
|
|
|
bool ObjCInterfaceDecl::isDesignatedInitializer(Selector Sel,
|
|
|
|
const ObjCMethodDecl **InitMethod) const {
|
2017-04-26 13:06:20 +08:00
|
|
|
bool HasCompleteDef = isThisDeclarationADefinition();
|
|
|
|
// During deserialization the data record for the ObjCInterfaceDecl could
|
|
|
|
// be made invariant by reusing the canonical decl. Take this into account
|
|
|
|
// when checking for the complete definition.
|
|
|
|
if (!HasCompleteDef && getCanonicalDecl()->hasDefinition() &&
|
|
|
|
getCanonicalDecl()->getDefinition() == getDefinition())
|
|
|
|
HasCompleteDef = true;
|
|
|
|
|
2014-03-12 02:56:18 +08:00
|
|
|
// Check for a complete definition and recover if not so.
|
2017-04-26 13:06:20 +08:00
|
|
|
if (!HasCompleteDef)
|
2014-03-12 02:56:18 +08:00
|
|
|
return false;
|
2017-04-26 13:06:20 +08:00
|
|
|
|
2013-12-04 05:11:36 +08:00
|
|
|
if (data().ExternallyCompleted)
|
|
|
|
LoadExternalDefinition();
|
|
|
|
|
2013-12-05 15:07:03 +08:00
|
|
|
const ObjCInterfaceDecl *IFace= findInterfaceWithDesignatedInitializers();
|
2013-12-04 05:11:36 +08:00
|
|
|
if (!IFace)
|
|
|
|
return false;
|
|
|
|
|
2014-03-29 06:45:38 +08:00
|
|
|
if (const ObjCMethodDecl *MD = IFace->getInstanceMethod(Sel)) {
|
2013-12-04 05:11:36 +08:00
|
|
|
if (MD->isThisDeclarationADesignatedInitializer()) {
|
|
|
|
if (InitMethod)
|
|
|
|
*InitMethod = MD;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2014-03-29 06:45:38 +08:00
|
|
|
for (const auto *Ext : IFace->visible_extensions()) {
|
|
|
|
if (const ObjCMethodDecl *MD = Ext->getInstanceMethod(Sel)) {
|
|
|
|
if (MD->isThisDeclarationADesignatedInitializer()) {
|
|
|
|
if (InitMethod)
|
|
|
|
*InitMethod = MD;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-12-04 05:11:36 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-12-15 13:27:12 +08:00
|
|
|
void ObjCInterfaceDecl::allocateDefinitionData() {
|
|
|
|
assert(!hasDefinition() && "ObjC class already has a definition");
|
Ensure that type definitions present in just-loaded modules are
visible.
The basic problem here is that a given translation unit can use
forward declarations to form pointers to a given type, say,
class X;
X *x;
and then import a module that includes a definition of X:
import XDef;
We will then fail when attempting to access a member of X, e.g.,
x->method()
because the AST reader did not know to look for a default of a class
named X within the new module.
This implementation is a bit of a C-centric hack, because the only
definitions that can have this property are enums, structs, unions,
Objective-C classes, and Objective-C protocols, and all of those are
either visible at the top-level or can't be defined later. Hence, we
can use the out-of-date-ness of the name and the identifier-update
mechanism to force the update.
In C++, we will not be so lucky, and will need a more advanced
solution, because the definitions could be in namespaces defined in
two different modules, e.g.,
// module 1
namespace N { struct X; }
// module 2
namespace N { struct X { /* ... */ }; }
One possible implementation here is for C++ to extend the information
associated with each identifier table to include the declaration IDs
of any definitions associated with that name, regardless of
context. We would have to eagerly load those definitions.
llvm-svn: 174794
2013-02-09 09:35:03 +08:00
|
|
|
Data.setPointer(new (getASTContext()) DefinitionData());
|
|
|
|
Data.getPointer()->Definition = this;
|
2011-12-16 11:12:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ObjCInterfaceDecl::startDefinition() {
|
|
|
|
allocateDefinitionData();
|
|
|
|
|
2011-12-16 02:03:09 +08:00
|
|
|
// Update all of the declarations with a pointer to the definition.
|
2018-04-10 06:14:10 +08:00
|
|
|
for (auto *RD : redecls()) {
|
2014-03-07 07:45:36 +08:00
|
|
|
if (RD != this)
|
2011-12-16 02:17:27 +08:00
|
|
|
RD->Data = Data;
|
2011-12-16 02:03:09 +08:00
|
|
|
}
|
2011-11-13 05:07:46 +08:00
|
|
|
}
|
|
|
|
|
2009-06-30 10:36:12 +08:00
|
|
|
ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
|
|
|
|
ObjCInterfaceDecl *&clsDeclared) {
|
2011-12-15 13:27:12 +08:00
|
|
|
// FIXME: Should make sure no callers ever do this.
|
|
|
|
if (!hasDefinition())
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2011-12-15 13:27:12 +08:00
|
|
|
|
|
|
|
if (data().ExternallyCompleted)
|
2011-10-19 10:25:16 +08:00
|
|
|
LoadExternalDefinition();
|
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
ObjCInterfaceDecl* ClassDecl = this;
|
2014-05-12 13:36:57 +08:00
|
|
|
while (ClassDecl != nullptr) {
|
2009-06-30 10:36:12 +08:00
|
|
|
if (ObjCIvarDecl *I = ClassDecl->getIvarDecl(ID)) {
|
2009-06-06 02:16:35 +08:00
|
|
|
clsDeclared = ClassDecl;
|
|
|
|
return I;
|
2009-02-21 04:59:54 +08:00
|
|
|
}
|
2013-01-17 07:00:23 +08:00
|
|
|
|
2014-03-14 05:47:07 +08:00
|
|
|
for (const auto *Ext : ClassDecl->visible_extensions()) {
|
2013-01-17 07:00:23 +08:00
|
|
|
if (ObjCIvarDecl *I = Ext->getIvarDecl(ID)) {
|
2010-02-23 09:26:30 +08:00
|
|
|
clsDeclared = ClassDecl;
|
|
|
|
return I;
|
|
|
|
}
|
2010-06-23 07:20:40 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
ClassDecl = ClassDecl->getSuperClass();
|
|
|
|
}
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2009-02-21 04:59:54 +08:00
|
|
|
}
|
|
|
|
|
2009-05-23 01:12:32 +08:00
|
|
|
/// lookupInheritedClass - This method returns ObjCInterfaceDecl * of the super
|
|
|
|
/// class whose name is passed as argument. If it is not one of the super classes
|
|
|
|
/// the it returns NULL.
|
|
|
|
ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass(
|
|
|
|
const IdentifierInfo*ICName) {
|
2011-12-15 13:27:12 +08:00
|
|
|
// FIXME: Should make sure no callers ever do this.
|
|
|
|
if (!hasDefinition())
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2011-12-15 13:27:12 +08:00
|
|
|
|
|
|
|
if (data().ExternallyCompleted)
|
2011-10-19 10:25:16 +08:00
|
|
|
LoadExternalDefinition();
|
|
|
|
|
2009-05-23 01:12:32 +08:00
|
|
|
ObjCInterfaceDecl* ClassDecl = this;
|
2014-05-12 13:36:57 +08:00
|
|
|
while (ClassDecl != nullptr) {
|
2009-05-23 01:12:32 +08:00
|
|
|
if (ClassDecl->getIdentifier() == ICName)
|
|
|
|
return ClassDecl;
|
|
|
|
ClassDecl = ClassDecl->getSuperClass();
|
|
|
|
}
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2009-05-23 01:12:32 +08:00
|
|
|
}
|
|
|
|
|
2013-07-11 05:30:22 +08:00
|
|
|
ObjCProtocolDecl *
|
|
|
|
ObjCInterfaceDecl::lookupNestedProtocol(IdentifierInfo *Name) {
|
2014-03-14 04:55:22 +08:00
|
|
|
for (auto *P : all_referenced_protocols())
|
|
|
|
if (P->lookupProtocolNamed(Name))
|
|
|
|
return P;
|
2013-07-11 05:30:22 +08:00
|
|
|
ObjCInterfaceDecl *SuperClass = getSuperClass();
|
2014-05-12 13:36:57 +08:00
|
|
|
return SuperClass ? SuperClass->lookupNestedProtocol(Name) : nullptr;
|
2013-07-11 05:30:22 +08:00
|
|
|
}
|
|
|
|
|
2009-07-26 06:15:51 +08:00
|
|
|
/// lookupMethod - This method returns an instance/class method by looking in
|
2009-02-21 04:59:54 +08:00
|
|
|
/// the class, its categories, and its super classes (using a linear search).
|
2013-04-26 05:59:34 +08:00
|
|
|
/// When argument category "C" is specified, any implicit method found
|
|
|
|
/// in this category is ignored.
|
2018-07-31 03:24:48 +08:00
|
|
|
ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
|
2013-11-23 09:01:29 +08:00
|
|
|
bool isInstance,
|
|
|
|
bool shallowCategoryLookup,
|
|
|
|
bool followSuper,
|
2013-12-11 03:43:48 +08:00
|
|
|
const ObjCCategoryDecl *C) const
|
2013-11-23 09:01:29 +08:00
|
|
|
{
|
2011-12-15 13:27:12 +08:00
|
|
|
// FIXME: Should make sure no callers ever do this.
|
|
|
|
if (!hasDefinition())
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2011-12-15 13:27:12 +08:00
|
|
|
|
2009-07-26 06:15:51 +08:00
|
|
|
const ObjCInterfaceDecl* ClassDecl = this;
|
2014-05-12 13:36:57 +08:00
|
|
|
ObjCMethodDecl *MethodDecl = nullptr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-12-15 13:27:12 +08:00
|
|
|
if (data().ExternallyCompleted)
|
2010-12-02 07:49:52 +08:00
|
|
|
LoadExternalDefinition();
|
|
|
|
|
2013-11-23 09:01:29 +08:00
|
|
|
while (ClassDecl) {
|
2014-08-28 04:34:29 +08:00
|
|
|
// 1. Look through primary class.
|
2009-07-26 06:15:51 +08:00
|
|
|
if ((MethodDecl = ClassDecl->getMethod(Sel, isInstance)))
|
2009-02-21 04:59:54 +08:00
|
|
|
return MethodDecl;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2014-08-28 04:34:29 +08:00
|
|
|
// 2. Didn't find one yet - now look through categories.
|
|
|
|
for (const auto *Cat : ClassDecl->visible_categories())
|
2013-04-26 05:59:34 +08:00
|
|
|
if ((MethodDecl = Cat->getMethod(Sel, isInstance)))
|
2014-03-14 05:23:55 +08:00
|
|
|
if (C != Cat || !MethodDecl->isImplicit())
|
2013-04-25 01:06:38 +08:00
|
|
|
return MethodDecl;
|
|
|
|
|
2014-08-28 04:34:29 +08:00
|
|
|
// 3. Didn't find one yet - look through primary class's protocols.
|
|
|
|
for (const auto *I : ClassDecl->protocols())
|
|
|
|
if ((MethodDecl = I->lookupMethod(Sel, isInstance)))
|
|
|
|
return MethodDecl;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2014-08-28 04:34:29 +08:00
|
|
|
// 4. Didn't find one yet - now look through categories' protocols
|
|
|
|
if (!shallowCategoryLookup)
|
|
|
|
for (const auto *Cat : ClassDecl->visible_categories()) {
|
2013-04-26 05:59:34 +08:00
|
|
|
// Didn't find one yet - look through protocols.
|
|
|
|
const ObjCList<ObjCProtocolDecl> &Protocols =
|
2014-08-28 04:34:29 +08:00
|
|
|
Cat->getReferencedProtocols();
|
2018-04-10 06:14:10 +08:00
|
|
|
for (auto *Protocol : Protocols)
|
|
|
|
if ((MethodDecl = Protocol->lookupMethod(Sel, isInstance)))
|
2014-03-14 05:23:55 +08:00
|
|
|
if (C != Cat || !MethodDecl->isImplicit())
|
2013-04-25 01:06:38 +08:00
|
|
|
return MethodDecl;
|
2012-02-10 05:30:24 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
|
|
|
|
2013-11-23 09:01:29 +08:00
|
|
|
if (!followSuper)
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2013-11-23 09:01:29 +08:00
|
|
|
|
2014-08-28 04:34:29 +08:00
|
|
|
// 5. Get to the super class (if any).
|
2009-02-21 04:59:54 +08:00
|
|
|
ClassDecl = ClassDecl->getSuperClass();
|
|
|
|
}
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2009-02-21 04:59:54 +08:00
|
|
|
}
|
|
|
|
|
2012-07-28 03:07:44 +08:00
|
|
|
// Will search "local" class/category implementations for a method decl.
|
|
|
|
// If failed, then we search in class's root for an instance method.
|
|
|
|
// Returns 0 if no method is found.
|
2010-12-04 07:37:08 +08:00
|
|
|
ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod(
|
|
|
|
const Selector &Sel,
|
2012-07-31 04:31:21 +08:00
|
|
|
bool Instance) const {
|
2011-12-15 13:27:12 +08:00
|
|
|
// FIXME: Should make sure no callers ever do this.
|
|
|
|
if (!hasDefinition())
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2011-12-15 13:27:12 +08:00
|
|
|
|
|
|
|
if (data().ExternallyCompleted)
|
2011-10-19 10:25:16 +08:00
|
|
|
LoadExternalDefinition();
|
|
|
|
|
2014-05-12 13:36:57 +08:00
|
|
|
ObjCMethodDecl *Method = nullptr;
|
2009-10-02 07:46:04 +08:00
|
|
|
if (ObjCImplementationDecl *ImpDecl = getImplementation())
|
2018-07-31 03:24:48 +08:00
|
|
|
Method = Instance ? ImpDecl->getInstanceMethod(Sel)
|
2010-12-04 07:37:08 +08:00
|
|
|
: ImpDecl->getClassMethod(Sel);
|
2012-07-28 03:07:44 +08:00
|
|
|
|
|
|
|
// Look through local category implementations associated with the class.
|
|
|
|
if (!Method)
|
2015-03-02 09:12:28 +08:00
|
|
|
Method = getCategoryMethod(Sel, Instance);
|
2012-07-28 03:07:44 +08:00
|
|
|
|
|
|
|
// Before we give up, check if the selector is an instance method.
|
|
|
|
// But only in the root. This matches gcc's behavior and what the
|
|
|
|
// runtime expects.
|
|
|
|
if (!Instance && !Method && !getSuperClass()) {
|
|
|
|
Method = lookupInstanceMethod(Sel);
|
|
|
|
// Look through local category implementations associated
|
|
|
|
// with the root class.
|
|
|
|
if (!Method)
|
|
|
|
Method = lookupPrivateMethod(Sel, true);
|
|
|
|
}
|
|
|
|
|
2009-10-02 07:46:04 +08:00
|
|
|
if (!Method && getSuperClass())
|
2010-12-04 07:37:08 +08:00
|
|
|
return getSuperClass()->lookupPrivateMethod(Sel, Instance);
|
2009-10-02 07:46:04 +08:00
|
|
|
return Method;
|
|
|
|
}
|
2009-02-21 04:59:54 +08:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ObjCMethodDecl
|
2008-03-16 08:49:28 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-11-05 06:28:14 +08:00
|
|
|
ObjCMethodDecl::ObjCMethodDecl(
|
|
|
|
SourceLocation beginLoc, SourceLocation endLoc, Selector SelInfo,
|
|
|
|
QualType T, TypeSourceInfo *ReturnTInfo, DeclContext *contextDecl,
|
|
|
|
bool isInstance, bool isVariadic, bool isPropertyAccessor,
|
|
|
|
bool isSynthesizedAccessorStub, bool isImplicitlyDeclared, bool isDefined,
|
|
|
|
ImplementationControl impControl, bool HasRelatedResultType)
|
2018-08-02 05:31:08 +08:00
|
|
|
: NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
|
|
|
|
DeclContext(ObjCMethod), MethodDeclType(T), ReturnTInfo(ReturnTInfo),
|
|
|
|
DeclEndLoc(endLoc) {
|
|
|
|
|
|
|
|
// Initialized the bits stored in DeclContext.
|
|
|
|
ObjCMethodDeclBits.Family =
|
|
|
|
static_cast<ObjCMethodFamily>(InvalidObjCMethodFamily);
|
|
|
|
setInstanceMethod(isInstance);
|
|
|
|
setVariadic(isVariadic);
|
|
|
|
setPropertyAccessor(isPropertyAccessor);
|
2019-11-05 06:28:14 +08:00
|
|
|
setSynthesizedAccessorStub(isSynthesizedAccessorStub);
|
2018-08-02 05:31:08 +08:00
|
|
|
setDefined(isDefined);
|
|
|
|
setIsRedeclaration(false);
|
|
|
|
setHasRedeclaration(false);
|
|
|
|
setDeclImplementation(impControl);
|
|
|
|
setObjCDeclQualifier(OBJC_TQ_None);
|
|
|
|
setRelatedResultType(HasRelatedResultType);
|
|
|
|
setSelLocsKind(SelLoc_StandardNoSpace);
|
|
|
|
setOverriding(false);
|
|
|
|
setHasSkippedBody(false);
|
|
|
|
|
|
|
|
setImplicit(isImplicitlyDeclared);
|
|
|
|
}
|
|
|
|
|
2014-01-26 00:55:45 +08:00
|
|
|
ObjCMethodDecl *ObjCMethodDecl::Create(
|
|
|
|
ASTContext &C, SourceLocation beginLoc, SourceLocation endLoc,
|
|
|
|
Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo,
|
|
|
|
DeclContext *contextDecl, bool isInstance, bool isVariadic,
|
2019-11-05 06:28:14 +08:00
|
|
|
bool isPropertyAccessor, bool isSynthesizedAccessorStub,
|
|
|
|
bool isImplicitlyDeclared, bool isDefined, ImplementationControl impControl,
|
|
|
|
bool HasRelatedResultType) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, contextDecl) ObjCMethodDecl(
|
2014-01-26 00:55:45 +08:00
|
|
|
beginLoc, endLoc, SelInfo, T, ReturnTInfo, contextDecl, isInstance,
|
2019-11-05 06:28:14 +08:00
|
|
|
isVariadic, isPropertyAccessor, isSynthesizedAccessorStub,
|
|
|
|
isImplicitlyDeclared, isDefined, impControl, HasRelatedResultType);
|
2008-03-16 09:15:50 +08:00
|
|
|
}
|
|
|
|
|
2012-01-06 05:55:30 +08:00
|
|
|
ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, ID) ObjCMethodDecl(SourceLocation(), SourceLocation(),
|
2014-05-12 13:36:57 +08:00
|
|
|
Selector(), QualType(), nullptr, nullptr);
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
Implement __attribute__((objc_direct)), __attribute__((objc_direct_members))
__attribute__((objc_direct)) is an attribute on methods declaration, and
__attribute__((objc_direct_members)) on implementation, categories or
extensions.
A `direct` property specifier is added (@property(direct) type name)
These attributes / specifiers cause the method to have no associated
Objective-C metadata (for the property or the method itself), and the
calling convention to be a direct C function call.
The symbol for the method has enforced hidden visibility and such direct
calls are hence unreachable cross image. An explicit C function must be
made if so desired to wrap them.
The implicit `self` and `_cmd` arguments are preserved, however to
maintain compatibility with the usual `objc_msgSend` semantics,
3 fundamental precautions are taken:
1) for instance methods, `self` is nil-checked. On arm64 backends this
typically adds a single instruction (cbz x0, <closest-ret>) to the
codegen, for the vast majority of the cases when the return type is a
scalar.
2) for class methods, because the class may not be realized/initialized
yet, a call to `[self self]` is emitted. When the proper deployment
target is used, this is optimized to `objc_opt_self(self)`.
However, long term we might want to emit something better that the
optimizer can reason about. When inlining kicks in, these calls
aren't optimized away as the optimizer has no idea that a single call
is really necessary.
3) the calling convention for the `_cmd` argument is changed: the caller
leaves the second argument to the call undefined, and the selector is
loaded inside the body when it's referenced only.
As far as error reporting goes, the compiler refuses:
- making any overloads direct,
- making an overload of a direct method,
- implementations marked as direct when the declaration in the
interface isn't (the other way around is allowed, as the direct
attribute is inherited from the declaration),
- marking methods required for protocol conformance as direct,
- messaging an unqualified `id` with a direct method,
- forming any @selector() expression with only direct selectors.
As warnings:
- any inconsistency of direct-related calling convention when
@selector() or messaging is used,
- forming any @selector() expression with a possibly direct selector.
Lastly an `objc_direct_members` attribute is added that can decorate
`@implementation` blocks and causes methods only declared there (and in
no `@interface`) to be automatically direct. When decorating an
`@interface` then all methods and properties declared in this block are
marked direct.
Radar-ID: rdar://problem/2684889
Differential Revision: https://reviews.llvm.org/D69991
Reviewed-By: John McCall
2019-11-08 15:14:58 +08:00
|
|
|
bool ObjCMethodDecl::isDirectMethod() const {
|
2021-04-06 07:23:27 +08:00
|
|
|
return hasAttr<ObjCDirectAttr>() &&
|
|
|
|
!getASTContext().getLangOpts().ObjCDisableDirectMethodsForTesting;
|
Implement __attribute__((objc_direct)), __attribute__((objc_direct_members))
__attribute__((objc_direct)) is an attribute on methods declaration, and
__attribute__((objc_direct_members)) on implementation, categories or
extensions.
A `direct` property specifier is added (@property(direct) type name)
These attributes / specifiers cause the method to have no associated
Objective-C metadata (for the property or the method itself), and the
calling convention to be a direct C function call.
The symbol for the method has enforced hidden visibility and such direct
calls are hence unreachable cross image. An explicit C function must be
made if so desired to wrap them.
The implicit `self` and `_cmd` arguments are preserved, however to
maintain compatibility with the usual `objc_msgSend` semantics,
3 fundamental precautions are taken:
1) for instance methods, `self` is nil-checked. On arm64 backends this
typically adds a single instruction (cbz x0, <closest-ret>) to the
codegen, for the vast majority of the cases when the return type is a
scalar.
2) for class methods, because the class may not be realized/initialized
yet, a call to `[self self]` is emitted. When the proper deployment
target is used, this is optimized to `objc_opt_self(self)`.
However, long term we might want to emit something better that the
optimizer can reason about. When inlining kicks in, these calls
aren't optimized away as the optimizer has no idea that a single call
is really necessary.
3) the calling convention for the `_cmd` argument is changed: the caller
leaves the second argument to the call undefined, and the selector is
loaded inside the body when it's referenced only.
As far as error reporting goes, the compiler refuses:
- making any overloads direct,
- making an overload of a direct method,
- implementations marked as direct when the declaration in the
interface isn't (the other way around is allowed, as the direct
attribute is inherited from the declaration),
- marking methods required for protocol conformance as direct,
- messaging an unqualified `id` with a direct method,
- forming any @selector() expression with only direct selectors.
As warnings:
- any inconsistency of direct-related calling convention when
@selector() or messaging is used,
- forming any @selector() expression with a possibly direct selector.
Lastly an `objc_direct_members` attribute is added that can decorate
`@implementation` blocks and causes methods only declared there (and in
no `@interface`) to be automatically direct. When decorating an
`@interface` then all methods and properties declared in this block are
marked direct.
Radar-ID: rdar://problem/2684889
Differential Revision: https://reviews.llvm.org/D69991
Reviewed-By: John McCall
2019-11-08 15:14:58 +08:00
|
|
|
}
|
|
|
|
|
2013-12-04 05:11:36 +08:00
|
|
|
bool ObjCMethodDecl::isThisDeclarationADesignatedInitializer() const {
|
|
|
|
return getMethodFamily() == OMF_init &&
|
|
|
|
hasAttr<ObjCDesignatedInitializerAttr>();
|
|
|
|
}
|
|
|
|
|
2018-09-11 06:20:09 +08:00
|
|
|
bool ObjCMethodDecl::definedInNSObject(const ASTContext &Ctx) const {
|
|
|
|
if (const auto *PD = dyn_cast<const ObjCProtocolDecl>(getDeclContext()))
|
|
|
|
return PD->getIdentifier() == Ctx.getNSObjectName();
|
|
|
|
if (const auto *ID = dyn_cast<const ObjCInterfaceDecl>(getDeclContext()))
|
|
|
|
return ID->getIdentifier() == Ctx.getNSObjectName();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-12-04 05:11:43 +08:00
|
|
|
bool ObjCMethodDecl::isDesignatedInitializerForTheInterface(
|
|
|
|
const ObjCMethodDecl **InitMethod) const {
|
|
|
|
if (getMethodFamily() != OMF_init)
|
|
|
|
return false;
|
2013-12-04 05:11:36 +08:00
|
|
|
const DeclContext *DC = getDeclContext();
|
|
|
|
if (isa<ObjCProtocolDecl>(DC))
|
|
|
|
return false;
|
|
|
|
if (const ObjCInterfaceDecl *ID = getClassInterface())
|
2013-12-04 05:11:43 +08:00
|
|
|
return ID->isDesignatedInitializer(getSelector(), InitMethod);
|
2013-12-04 05:11:36 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-10-08 17:20:45 +08:00
|
|
|
bool ObjCMethodDecl::hasParamDestroyedInCallee() const {
|
|
|
|
for (auto param : parameters()) {
|
|
|
|
if (param->isDestroyedInCallee())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-10-10 01:21:28 +08:00
|
|
|
Stmt *ObjCMethodDecl::getBody() const {
|
|
|
|
return Body.get(getASTContext().getExternalSource());
|
|
|
|
}
|
|
|
|
|
2011-10-14 16:02:31 +08:00
|
|
|
void ObjCMethodDecl::setAsRedeclaration(const ObjCMethodDecl *PrevMethod) {
|
|
|
|
assert(PrevMethod);
|
|
|
|
getASTContext().setObjCMethodRedeclaration(PrevMethod, this);
|
2018-08-02 05:31:08 +08:00
|
|
|
setIsRedeclaration(true);
|
|
|
|
PrevMethod->setHasRedeclaration(true);
|
2011-10-14 16:02:31 +08:00
|
|
|
}
|
|
|
|
|
2011-10-03 14:37:04 +08:00
|
|
|
void ObjCMethodDecl::setParamsAndSelLocs(ASTContext &C,
|
|
|
|
ArrayRef<ParmVarDecl*> Params,
|
|
|
|
ArrayRef<SourceLocation> SelLocs) {
|
2014-05-12 13:36:57 +08:00
|
|
|
ParamsAndSelLocs = nullptr;
|
2011-10-03 14:37:04 +08:00
|
|
|
NumParams = Params.size();
|
|
|
|
if (Params.empty() && SelLocs.empty())
|
|
|
|
return;
|
|
|
|
|
2016-10-20 22:27:22 +08:00
|
|
|
static_assert(alignof(ParmVarDecl *) >= alignof(SourceLocation),
|
2015-12-30 06:13:13 +08:00
|
|
|
"Alignment not sufficient for SourceLocation");
|
|
|
|
|
2011-10-03 14:37:04 +08:00
|
|
|
unsigned Size = sizeof(ParmVarDecl *) * NumParams +
|
|
|
|
sizeof(SourceLocation) * SelLocs.size();
|
|
|
|
ParamsAndSelLocs = C.Allocate(Size);
|
|
|
|
std::copy(Params.begin(), Params.end(), getParams());
|
|
|
|
std::copy(SelLocs.begin(), SelLocs.end(), getStoredSelLocs());
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObjCMethodDecl::getSelectorLocs(
|
|
|
|
SmallVectorImpl<SourceLocation> &SelLocs) const {
|
|
|
|
for (unsigned i = 0, e = getNumSelectorLocs(); i != e; ++i)
|
|
|
|
SelLocs.push_back(getSelectorLoc(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObjCMethodDecl::setMethodParams(ASTContext &C,
|
|
|
|
ArrayRef<ParmVarDecl*> Params,
|
|
|
|
ArrayRef<SourceLocation> SelLocs) {
|
|
|
|
assert((!SelLocs.empty() || isImplicit()) &&
|
|
|
|
"No selector locs for non-implicit method");
|
|
|
|
if (isImplicit())
|
2013-05-05 08:41:58 +08:00
|
|
|
return setParamsAndSelLocs(C, Params, llvm::None);
|
2011-10-03 14:37:04 +08:00
|
|
|
|
2018-08-02 05:31:08 +08:00
|
|
|
setSelLocsKind(hasStandardSelectorLocs(getSelector(), SelLocs, Params,
|
|
|
|
DeclEndLoc));
|
|
|
|
if (getSelLocsKind() != SelLoc_NonStandard)
|
2013-05-05 08:41:58 +08:00
|
|
|
return setParamsAndSelLocs(C, Params, llvm::None);
|
2011-10-03 14:37:04 +08:00
|
|
|
|
|
|
|
setParamsAndSelLocs(C, Params, SelLocs);
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// A definition will return its interface declaration.
|
2009-07-21 08:06:36 +08:00
|
|
|
/// An interface declaration will return its definition.
|
|
|
|
/// Otherwise it will return itself.
|
2014-05-10 09:17:36 +08:00
|
|
|
ObjCMethodDecl *ObjCMethodDecl::getNextRedeclarationImpl() {
|
2009-07-21 08:06:36 +08:00
|
|
|
ASTContext &Ctx = getASTContext();
|
2014-05-12 13:36:57 +08:00
|
|
|
ObjCMethodDecl *Redecl = nullptr;
|
2018-08-02 05:31:08 +08:00
|
|
|
if (hasRedeclaration())
|
2011-10-15 01:41:52 +08:00
|
|
|
Redecl = const_cast<ObjCMethodDecl*>(Ctx.getObjCMethodRedeclaration(this));
|
2011-10-14 14:48:06 +08:00
|
|
|
if (Redecl)
|
|
|
|
return Redecl;
|
|
|
|
|
2018-04-10 06:14:10 +08:00
|
|
|
auto *CtxD = cast<Decl>(getDeclContext());
|
2009-07-21 08:06:36 +08:00
|
|
|
|
2013-05-31 02:53:21 +08:00
|
|
|
if (!CtxD->isInvalidDecl()) {
|
2018-04-10 06:14:10 +08:00
|
|
|
if (auto *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) {
|
2013-05-31 02:53:21 +08:00
|
|
|
if (ObjCImplementationDecl *ImplD = Ctx.getObjCImplementation(IFD))
|
|
|
|
if (!ImplD->isInvalidDecl())
|
|
|
|
Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
|
|
|
|
|
2018-04-10 06:14:10 +08:00
|
|
|
} else if (auto *CD = dyn_cast<ObjCCategoryDecl>(CtxD)) {
|
2013-05-31 02:53:21 +08:00
|
|
|
if (ObjCCategoryImplDecl *ImplD = Ctx.getObjCImplementation(CD))
|
|
|
|
if (!ImplD->isInvalidDecl())
|
|
|
|
Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
|
|
|
|
|
2018-04-10 06:14:10 +08:00
|
|
|
} else if (auto *ImplD = dyn_cast<ObjCImplementationDecl>(CtxD)) {
|
2013-05-31 02:53:21 +08:00
|
|
|
if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface())
|
|
|
|
if (!IFD->isInvalidDecl())
|
|
|
|
Redecl = IFD->getMethod(getSelector(), isInstanceMethod());
|
|
|
|
|
2018-04-10 06:14:10 +08:00
|
|
|
} else if (auto *CImplD = dyn_cast<ObjCCategoryImplDecl>(CtxD)) {
|
2013-05-31 02:53:21 +08:00
|
|
|
if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl())
|
|
|
|
if (!CatD->isInvalidDecl())
|
|
|
|
Redecl = CatD->getMethod(getSelector(), isInstanceMethod());
|
|
|
|
}
|
2009-07-21 08:06:36 +08:00
|
|
|
}
|
|
|
|
|
2016-11-21 19:16:30 +08:00
|
|
|
// Ensure that the discovered method redeclaration has a valid declaration
|
|
|
|
// context. Used to prevent infinite loops when iterating redeclarations in
|
|
|
|
// a partially invalid AST.
|
|
|
|
if (Redecl && cast<Decl>(Redecl->getDeclContext())->isInvalidDecl())
|
|
|
|
Redecl = nullptr;
|
|
|
|
|
2011-10-14 16:02:31 +08:00
|
|
|
if (!Redecl && isRedeclaration()) {
|
|
|
|
// This is the last redeclaration, go back to the first method.
|
|
|
|
return cast<ObjCContainerDecl>(CtxD)->getMethod(getSelector(),
|
2020-10-09 10:48:33 +08:00
|
|
|
isInstanceMethod(),
|
|
|
|
/*AllowHidden=*/true);
|
2011-10-14 16:02:31 +08:00
|
|
|
}
|
|
|
|
|
2009-07-21 08:06:36 +08:00
|
|
|
return Redecl ? Redecl : this;
|
|
|
|
}
|
|
|
|
|
2009-07-28 13:11:17 +08:00
|
|
|
ObjCMethodDecl *ObjCMethodDecl::getCanonicalDecl() {
|
2018-04-10 06:14:10 +08:00
|
|
|
auto *CtxD = cast<Decl>(getDeclContext());
|
2019-12-19 17:25:03 +08:00
|
|
|
const auto &Sel = getSelector();
|
2009-07-28 13:11:17 +08:00
|
|
|
|
2018-04-10 06:14:10 +08:00
|
|
|
if (auto *ImplD = dyn_cast<ObjCImplementationDecl>(CtxD)) {
|
2019-12-18 03:06:17 +08:00
|
|
|
if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) {
|
2019-12-19 17:25:03 +08:00
|
|
|
// When the container is the ObjCImplementationDecl (the primary
|
|
|
|
// @implementation), then the canonical Decl is either in
|
|
|
|
// the class Interface, or in any of its extension.
|
|
|
|
//
|
|
|
|
// So when we don't find it in the ObjCInterfaceDecl,
|
|
|
|
// sift through extensions too.
|
|
|
|
if (ObjCMethodDecl *MD = IFD->getMethod(Sel, isInstanceMethod()))
|
2009-07-28 13:11:17 +08:00
|
|
|
return MD;
|
2019-12-19 17:25:03 +08:00
|
|
|
for (auto *Ext : IFD->known_extensions())
|
|
|
|
if (ObjCMethodDecl *MD = Ext->getMethod(Sel, isInstanceMethod()))
|
|
|
|
return MD;
|
2019-12-18 03:06:17 +08:00
|
|
|
}
|
2018-04-10 06:14:10 +08:00
|
|
|
} else if (auto *CImplD = dyn_cast<ObjCCategoryImplDecl>(CtxD)) {
|
2009-10-30 05:11:04 +08:00
|
|
|
if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl())
|
2019-12-19 17:25:03 +08:00
|
|
|
if (ObjCMethodDecl *MD = CatD->getMethod(Sel, isInstanceMethod()))
|
2009-07-28 13:11:17 +08:00
|
|
|
return MD;
|
|
|
|
}
|
|
|
|
|
2016-10-04 05:26:46 +08:00
|
|
|
if (isRedeclaration()) {
|
|
|
|
// It is possible that we have not done deserializing the ObjCMethod yet.
|
|
|
|
ObjCMethodDecl *MD =
|
2020-10-09 10:48:33 +08:00
|
|
|
cast<ObjCContainerDecl>(CtxD)->getMethod(Sel, isInstanceMethod(),
|
|
|
|
/*AllowHidden=*/true);
|
2016-10-04 05:26:46 +08:00
|
|
|
return MD ? MD : this;
|
|
|
|
}
|
2011-10-18 03:48:09 +08:00
|
|
|
|
2009-07-28 13:11:17 +08:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2018-08-10 04:05:47 +08:00
|
|
|
SourceLocation ObjCMethodDecl::getEndLoc() const {
|
2012-06-16 08:46:02 +08:00
|
|
|
if (Stmt *Body = getBody())
|
2018-08-10 05:09:38 +08:00
|
|
|
return Body->getEndLoc();
|
2012-06-16 08:46:02 +08:00
|
|
|
return DeclEndLoc;
|
|
|
|
}
|
|
|
|
|
2011-03-02 09:50:55 +08:00
|
|
|
ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
|
2018-08-02 05:31:08 +08:00
|
|
|
auto family = static_cast<ObjCMethodFamily>(ObjCMethodDeclBits.Family);
|
2011-03-03 05:01:41 +08:00
|
|
|
if (family != static_cast<unsigned>(InvalidObjCMethodFamily))
|
2011-03-02 09:50:55 +08:00
|
|
|
return family;
|
|
|
|
|
2011-03-02 19:33:24 +08:00
|
|
|
// Check for an explicit attribute.
|
|
|
|
if (const ObjCMethodFamilyAttr *attr = getAttr<ObjCMethodFamilyAttr>()) {
|
|
|
|
// The unfortunate necessity of mapping between enums here is due
|
|
|
|
// to the attributes framework.
|
|
|
|
switch (attr->getFamily()) {
|
|
|
|
case ObjCMethodFamilyAttr::OMF_None: family = OMF_None; break;
|
|
|
|
case ObjCMethodFamilyAttr::OMF_alloc: family = OMF_alloc; break;
|
|
|
|
case ObjCMethodFamilyAttr::OMF_copy: family = OMF_copy; break;
|
|
|
|
case ObjCMethodFamilyAttr::OMF_init: family = OMF_init; break;
|
|
|
|
case ObjCMethodFamilyAttr::OMF_mutableCopy: family = OMF_mutableCopy; break;
|
|
|
|
case ObjCMethodFamilyAttr::OMF_new: family = OMF_new; break;
|
|
|
|
}
|
2018-08-02 05:31:08 +08:00
|
|
|
ObjCMethodDeclBits.Family = family;
|
2011-03-02 19:33:24 +08:00
|
|
|
return family;
|
|
|
|
}
|
|
|
|
|
2011-03-02 09:50:55 +08:00
|
|
|
family = getSelector().getMethodFamily();
|
|
|
|
switch (family) {
|
|
|
|
case OMF_None: break;
|
|
|
|
|
|
|
|
// init only has a conventional meaning for an instance method, and
|
|
|
|
// it has to return an object.
|
|
|
|
case OMF_init:
|
2014-01-26 00:55:45 +08:00
|
|
|
if (!isInstanceMethod() || !getReturnType()->isObjCObjectPointerType())
|
2011-03-02 09:50:55 +08:00
|
|
|
family = OMF_None;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// alloc/copy/new have a conventional meaning for both class and
|
|
|
|
// instance methods, but they require an object return.
|
|
|
|
case OMF_alloc:
|
|
|
|
case OMF_copy:
|
|
|
|
case OMF_mutableCopy:
|
|
|
|
case OMF_new:
|
2014-01-26 00:55:45 +08:00
|
|
|
if (!getReturnType()->isObjCObjectPointerType())
|
2011-03-02 09:50:55 +08:00
|
|
|
family = OMF_None;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// These selectors have a conventional meaning only for instance methods.
|
|
|
|
case OMF_dealloc:
|
2011-08-29 06:35:17 +08:00
|
|
|
case OMF_finalize:
|
2011-03-02 09:50:55 +08:00
|
|
|
case OMF_retain:
|
|
|
|
case OMF_release:
|
|
|
|
case OMF_autorelease:
|
|
|
|
case OMF_retainCount:
|
2011-06-11 09:09:30 +08:00
|
|
|
case OMF_self:
|
2011-03-02 09:50:55 +08:00
|
|
|
if (!isInstanceMethod())
|
|
|
|
family = OMF_None;
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2014-08-23 00:57:26 +08:00
|
|
|
case OMF_initialize:
|
|
|
|
if (isInstanceMethod() || !getReturnType()->isVoidType())
|
|
|
|
family = OMF_None;
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-07-06 06:38:59 +08:00
|
|
|
case OMF_performSelector:
|
2017-03-23 18:46:05 +08:00
|
|
|
if (!isInstanceMethod() || !getReturnType()->isObjCIdType())
|
2011-07-06 06:38:59 +08:00
|
|
|
family = OMF_None;
|
|
|
|
else {
|
|
|
|
unsigned noParams = param_size();
|
2017-03-23 18:46:05 +08:00
|
|
|
if (noParams < 1 || noParams > 3)
|
2011-07-06 06:38:59 +08:00
|
|
|
family = OMF_None;
|
|
|
|
else {
|
2014-01-26 01:32:04 +08:00
|
|
|
ObjCMethodDecl::param_type_iterator it = param_type_begin();
|
2011-07-06 06:38:59 +08:00
|
|
|
QualType ArgT = (*it);
|
|
|
|
if (!ArgT->isObjCSelType()) {
|
|
|
|
family = OMF_None;
|
|
|
|
break;
|
|
|
|
}
|
2017-03-23 18:46:05 +08:00
|
|
|
while (--noParams) {
|
|
|
|
it++;
|
|
|
|
ArgT = (*it);
|
|
|
|
if (!ArgT->isObjCIdType()) {
|
2011-07-06 06:38:59 +08:00
|
|
|
family = OMF_None;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-03-02 09:50:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Cache the result.
|
2018-08-02 05:31:08 +08:00
|
|
|
ObjCMethodDeclBits.Family = family;
|
2011-03-02 09:50:55 +08:00
|
|
|
return family;
|
|
|
|
}
|
|
|
|
|
2015-07-09 06:15:59 +08:00
|
|
|
QualType ObjCMethodDecl::getSelfType(ASTContext &Context,
|
|
|
|
const ObjCInterfaceDecl *OID,
|
|
|
|
bool &selfIsPseudoStrong,
|
Implement __attribute__((objc_direct)), __attribute__((objc_direct_members))
__attribute__((objc_direct)) is an attribute on methods declaration, and
__attribute__((objc_direct_members)) on implementation, categories or
extensions.
A `direct` property specifier is added (@property(direct) type name)
These attributes / specifiers cause the method to have no associated
Objective-C metadata (for the property or the method itself), and the
calling convention to be a direct C function call.
The symbol for the method has enforced hidden visibility and such direct
calls are hence unreachable cross image. An explicit C function must be
made if so desired to wrap them.
The implicit `self` and `_cmd` arguments are preserved, however to
maintain compatibility with the usual `objc_msgSend` semantics,
3 fundamental precautions are taken:
1) for instance methods, `self` is nil-checked. On arm64 backends this
typically adds a single instruction (cbz x0, <closest-ret>) to the
codegen, for the vast majority of the cases when the return type is a
scalar.
2) for class methods, because the class may not be realized/initialized
yet, a call to `[self self]` is emitted. When the proper deployment
target is used, this is optimized to `objc_opt_self(self)`.
However, long term we might want to emit something better that the
optimizer can reason about. When inlining kicks in, these calls
aren't optimized away as the optimizer has no idea that a single call
is really necessary.
3) the calling convention for the `_cmd` argument is changed: the caller
leaves the second argument to the call undefined, and the selector is
loaded inside the body when it's referenced only.
As far as error reporting goes, the compiler refuses:
- making any overloads direct,
- making an overload of a direct method,
- implementations marked as direct when the declaration in the
interface isn't (the other way around is allowed, as the direct
attribute is inherited from the declaration),
- marking methods required for protocol conformance as direct,
- messaging an unqualified `id` with a direct method,
- forming any @selector() expression with only direct selectors.
As warnings:
- any inconsistency of direct-related calling convention when
@selector() or messaging is used,
- forming any @selector() expression with a possibly direct selector.
Lastly an `objc_direct_members` attribute is added that can decorate
`@implementation` blocks and causes methods only declared there (and in
no `@interface`) to be automatically direct. When decorating an
`@interface` then all methods and properties declared in this block are
marked direct.
Radar-ID: rdar://problem/2684889
Differential Revision: https://reviews.llvm.org/D69991
Reviewed-By: John McCall
2019-11-08 15:14:58 +08:00
|
|
|
bool &selfIsConsumed) const {
|
2009-02-21 04:59:54 +08:00
|
|
|
QualType selfTy;
|
2015-07-09 06:15:59 +08:00
|
|
|
selfIsPseudoStrong = false;
|
|
|
|
selfIsConsumed = false;
|
2009-02-21 04:59:54 +08:00
|
|
|
if (isInstanceMethod()) {
|
|
|
|
// There may be no interface context due to error in declaration
|
|
|
|
// of the interface (which has been reported). Recover gracefully.
|
|
|
|
if (OID) {
|
2009-04-22 12:34:53 +08:00
|
|
|
selfTy = Context.getObjCInterfaceType(OID);
|
2009-07-11 07:34:53 +08:00
|
|
|
selfTy = Context.getObjCObjectPointerType(selfTy);
|
2009-02-21 04:59:54 +08:00
|
|
|
} else {
|
|
|
|
selfTy = Context.getObjCIdType();
|
|
|
|
}
|
|
|
|
} else // we have a factory method.
|
|
|
|
selfTy = Context.getObjCClassType();
|
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (Context.getLangOpts().ObjCAutoRefCount) {
|
2011-11-15 05:59:25 +08:00
|
|
|
if (isInstanceMethod()) {
|
|
|
|
selfIsConsumed = hasAttr<NSConsumesSelfAttr>();
|
|
|
|
|
|
|
|
// 'self' is always __strong. It's actually pseudo-strong except
|
|
|
|
// in init methods (or methods labeled ns_consumes_self), though.
|
|
|
|
Qualifiers qs;
|
|
|
|
qs.setObjCLifetime(Qualifiers::OCL_Strong);
|
|
|
|
selfTy = Context.getQualifiedType(selfTy, qs);
|
|
|
|
|
|
|
|
// In addition, 'self' is const unless this is an init method.
|
|
|
|
if (getMethodFamily() != OMF_init && !selfIsConsumed) {
|
|
|
|
selfTy = selfTy.withConst();
|
|
|
|
selfIsPseudoStrong = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
assert(isClassMethod());
|
|
|
|
// 'self' is always const in class methods.
|
2011-06-16 07:02:42 +08:00
|
|
|
selfTy = selfTy.withConst();
|
2011-06-17 14:42:21 +08:00
|
|
|
selfIsPseudoStrong = true;
|
|
|
|
}
|
2011-06-16 07:02:42 +08:00
|
|
|
}
|
2015-07-09 06:15:59 +08:00
|
|
|
return selfTy;
|
|
|
|
}
|
2011-06-16 07:02:42 +08:00
|
|
|
|
2015-07-09 06:15:59 +08:00
|
|
|
void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
|
|
|
|
const ObjCInterfaceDecl *OID) {
|
|
|
|
bool selfIsPseudoStrong, selfIsConsumed;
|
|
|
|
QualType selfTy =
|
|
|
|
getSelfType(Context, OID, selfIsPseudoStrong, selfIsConsumed);
|
2017-06-09 21:40:18 +08:00
|
|
|
auto *Self = ImplicitParamDecl::Create(Context, this, SourceLocation(),
|
|
|
|
&Context.Idents.get("self"), selfTy,
|
|
|
|
ImplicitParamDecl::ObjCSelf);
|
|
|
|
setSelfDecl(Self);
|
2011-06-16 07:02:42 +08:00
|
|
|
|
|
|
|
if (selfIsConsumed)
|
2017-06-09 21:40:18 +08:00
|
|
|
Self->addAttr(NSConsumedAttr::CreateImplicit(Context));
|
2009-02-21 04:59:54 +08:00
|
|
|
|
2011-06-17 14:42:21 +08:00
|
|
|
if (selfIsPseudoStrong)
|
2017-06-09 21:40:18 +08:00
|
|
|
Self->setARCPseudoStrong(true);
|
2011-06-17 14:42:21 +08:00
|
|
|
|
2017-06-09 21:40:18 +08:00
|
|
|
setCmdDecl(ImplicitParamDecl::Create(
|
|
|
|
Context, this, SourceLocation(), &Context.Idents.get("_cmd"),
|
|
|
|
Context.getObjCSelType(), ImplicitParamDecl::ObjCCmd));
|
2009-02-21 04:59:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() {
|
2018-04-10 06:14:10 +08:00
|
|
|
if (auto *ID = dyn_cast<ObjCInterfaceDecl>(getDeclContext()))
|
2009-02-21 04:59:54 +08:00
|
|
|
return ID;
|
2018-04-10 06:14:10 +08:00
|
|
|
if (auto *CD = dyn_cast<ObjCCategoryDecl>(getDeclContext()))
|
2009-02-21 04:59:54 +08:00
|
|
|
return CD->getClassInterface();
|
2018-04-10 06:14:10 +08:00
|
|
|
if (auto *IMD = dyn_cast<ObjCImplDecl>(getDeclContext()))
|
2009-02-21 04:59:54 +08:00
|
|
|
return IMD->getClassInterface();
|
2014-03-05 06:57:32 +08:00
|
|
|
if (isa<ObjCProtocolDecl>(getDeclContext()))
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2011-09-23 13:06:16 +08:00
|
|
|
llvm_unreachable("unknown method context");
|
2009-02-21 04:59:54 +08:00
|
|
|
}
|
|
|
|
|
2020-09-30 06:47:37 +08:00
|
|
|
ObjCCategoryDecl *ObjCMethodDecl::getCategory() {
|
|
|
|
if (auto *CD = dyn_cast<ObjCCategoryDecl>(getDeclContext()))
|
|
|
|
return CD;
|
|
|
|
if (auto *IMD = dyn_cast<ObjCCategoryImplDecl>(getDeclContext()))
|
|
|
|
return IMD->getCategoryDecl();
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2014-08-01 20:58:11 +08:00
|
|
|
SourceRange ObjCMethodDecl::getReturnTypeSourceRange() const {
|
|
|
|
const auto *TSI = getReturnTypeSourceInfo();
|
|
|
|
if (TSI)
|
|
|
|
return TSI->getTypeLoc().getSourceRange();
|
|
|
|
return SourceRange();
|
|
|
|
}
|
|
|
|
|
2015-07-07 14:20:27 +08:00
|
|
|
QualType ObjCMethodDecl::getSendResultType() const {
|
|
|
|
ASTContext &Ctx = getASTContext();
|
|
|
|
return getReturnType().getNonLValueExprType(Ctx)
|
|
|
|
.substObjCTypeArgs(Ctx, {}, ObjCSubstitutionContext::Result);
|
|
|
|
}
|
|
|
|
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 11:57:53 +08:00
|
|
|
QualType ObjCMethodDecl::getSendResultType(QualType receiverType) const {
|
|
|
|
// FIXME: Handle related result types here.
|
|
|
|
|
|
|
|
return getReturnType().getNonLValueExprType(getASTContext())
|
|
|
|
.substObjCMemberType(receiverType, getDeclContext(),
|
|
|
|
ObjCSubstitutionContext::Result);
|
|
|
|
}
|
|
|
|
|
2012-10-10 02:19:01 +08:00
|
|
|
static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
|
|
|
|
const ObjCMethodDecl *Method,
|
|
|
|
SmallVectorImpl<const ObjCMethodDecl *> &Methods,
|
|
|
|
bool MovedToSuper) {
|
|
|
|
if (!Container)
|
|
|
|
return;
|
|
|
|
|
2018-04-06 23:14:32 +08:00
|
|
|
// In categories look for overridden methods from protocols. A method from
|
|
|
|
// category is not "overridden" since it is considered as the "same" method
|
2012-10-10 02:19:01 +08:00
|
|
|
// (same USR) as the one from the interface.
|
2018-04-10 06:14:10 +08:00
|
|
|
if (const auto *Category = dyn_cast<ObjCCategoryDecl>(Container)) {
|
2012-10-10 02:19:01 +08:00
|
|
|
// Check whether we have a matching method at this category but only if we
|
|
|
|
// are at the super class level.
|
|
|
|
if (MovedToSuper)
|
|
|
|
if (ObjCMethodDecl *
|
|
|
|
Overridden = Container->getMethod(Method->getSelector(),
|
2013-03-30 05:51:48 +08:00
|
|
|
Method->isInstanceMethod(),
|
|
|
|
/*AllowHidden=*/true))
|
2012-10-10 02:19:01 +08:00
|
|
|
if (Method != Overridden) {
|
|
|
|
// We found an override at this category; there is no need to look
|
|
|
|
// into its protocols.
|
|
|
|
Methods.push_back(Overridden);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-03-14 20:55:57 +08:00
|
|
|
for (const auto *P : Category->protocols())
|
|
|
|
CollectOverriddenMethodsRecurse(P, Method, Methods, MovedToSuper);
|
2012-10-10 02:19:01 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether we have a matching method at this level.
|
|
|
|
if (const ObjCMethodDecl *
|
|
|
|
Overridden = Container->getMethod(Method->getSelector(),
|
2013-03-30 05:51:48 +08:00
|
|
|
Method->isInstanceMethod(),
|
|
|
|
/*AllowHidden=*/true))
|
2012-10-10 02:19:01 +08:00
|
|
|
if (Method != Overridden) {
|
|
|
|
// We found an override at this level; there is no need to look
|
|
|
|
// into other protocols or categories.
|
|
|
|
Methods.push_back(Overridden);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-04-10 06:14:10 +08:00
|
|
|
if (const auto *Protocol = dyn_cast<ObjCProtocolDecl>(Container)){
|
2014-03-14 06:58:06 +08:00
|
|
|
for (const auto *P : Protocol->protocols())
|
|
|
|
CollectOverriddenMethodsRecurse(P, Method, Methods, MovedToSuper);
|
2012-10-10 02:19:01 +08:00
|
|
|
}
|
|
|
|
|
2018-04-10 06:14:10 +08:00
|
|
|
if (const auto *Interface = dyn_cast<ObjCInterfaceDecl>(Container)) {
|
2014-03-14 04:29:09 +08:00
|
|
|
for (const auto *P : Interface->protocols())
|
|
|
|
CollectOverriddenMethodsRecurse(P, Method, Methods, MovedToSuper);
|
2012-10-10 02:19:01 +08:00
|
|
|
|
2014-03-14 05:35:02 +08:00
|
|
|
for (const auto *Cat : Interface->known_categories())
|
|
|
|
CollectOverriddenMethodsRecurse(Cat, Method, Methods, MovedToSuper);
|
2012-10-10 02:19:01 +08:00
|
|
|
|
|
|
|
if (const ObjCInterfaceDecl *Super = Interface->getSuperClass())
|
|
|
|
return CollectOverriddenMethodsRecurse(Super, Method, Methods,
|
|
|
|
/*MovedToSuper=*/true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void CollectOverriddenMethods(const ObjCContainerDecl *Container,
|
|
|
|
const ObjCMethodDecl *Method,
|
|
|
|
SmallVectorImpl<const ObjCMethodDecl *> &Methods) {
|
|
|
|
CollectOverriddenMethodsRecurse(Container, Method, Methods,
|
|
|
|
/*MovedToSuper=*/false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method,
|
|
|
|
SmallVectorImpl<const ObjCMethodDecl *> &overridden) {
|
|
|
|
assert(Method->isOverriding());
|
|
|
|
|
2018-04-10 06:14:10 +08:00
|
|
|
if (const auto *ProtD =
|
|
|
|
dyn_cast<ObjCProtocolDecl>(Method->getDeclContext())) {
|
2012-10-10 02:19:01 +08:00
|
|
|
CollectOverriddenMethods(ProtD, Method, overridden);
|
|
|
|
|
2018-04-10 06:14:10 +08:00
|
|
|
} else if (const auto *IMD =
|
|
|
|
dyn_cast<ObjCImplDecl>(Method->getDeclContext())) {
|
2012-10-10 02:19:01 +08:00
|
|
|
const ObjCInterfaceDecl *ID = IMD->getClassInterface();
|
|
|
|
if (!ID)
|
|
|
|
return;
|
|
|
|
// Start searching for overridden methods using the method from the
|
|
|
|
// interface as starting point.
|
|
|
|
if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
|
2013-03-30 05:51:48 +08:00
|
|
|
Method->isInstanceMethod(),
|
|
|
|
/*AllowHidden=*/true))
|
2012-10-10 02:19:01 +08:00
|
|
|
Method = IFaceMeth;
|
|
|
|
CollectOverriddenMethods(ID, Method, overridden);
|
|
|
|
|
2018-04-10 06:14:10 +08:00
|
|
|
} else if (const auto *CatD =
|
|
|
|
dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())) {
|
2012-10-10 02:19:01 +08:00
|
|
|
const ObjCInterfaceDecl *ID = CatD->getClassInterface();
|
|
|
|
if (!ID)
|
|
|
|
return;
|
|
|
|
// Start searching for overridden methods using the method from the
|
|
|
|
// interface as starting point.
|
|
|
|
if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
|
2013-03-30 05:51:48 +08:00
|
|
|
Method->isInstanceMethod(),
|
|
|
|
/*AllowHidden=*/true))
|
2012-10-10 02:19:01 +08:00
|
|
|
Method = IFaceMeth;
|
|
|
|
CollectOverriddenMethods(ID, Method, overridden);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
CollectOverriddenMethods(
|
|
|
|
dyn_cast_or_null<ObjCContainerDecl>(Method->getDeclContext()),
|
|
|
|
Method, overridden);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObjCMethodDecl::getOverriddenMethods(
|
|
|
|
SmallVectorImpl<const ObjCMethodDecl *> &Overridden) const {
|
|
|
|
const ObjCMethodDecl *Method = this;
|
|
|
|
|
|
|
|
if (Method->isRedeclaration()) {
|
2020-10-09 10:48:33 +08:00
|
|
|
Method = cast<ObjCContainerDecl>(Method->getDeclContext())
|
|
|
|
->getMethod(Method->getSelector(), Method->isInstanceMethod(),
|
|
|
|
/*AllowHidden=*/true);
|
2012-10-10 02:19:01 +08:00
|
|
|
}
|
|
|
|
|
2013-04-17 08:09:08 +08:00
|
|
|
if (Method->isOverriding()) {
|
2012-10-10 02:19:01 +08:00
|
|
|
collectOverriddenMethodsSlow(Method, Overridden);
|
|
|
|
assert(!Overridden.empty() &&
|
|
|
|
"ObjCMethodDecl's overriding bit is not as expected");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-11 00:42:54 +08:00
|
|
|
const ObjCPropertyDecl *
|
|
|
|
ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
|
|
|
|
Selector Sel = getSelector();
|
|
|
|
unsigned NumArgs = Sel.getNumArgs();
|
|
|
|
if (NumArgs > 1)
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2012-10-11 00:42:54 +08:00
|
|
|
|
|
|
|
if (isPropertyAccessor()) {
|
2018-04-10 06:14:10 +08:00
|
|
|
const auto *Container = cast<ObjCContainerDecl>(getParent());
|
2019-11-05 06:28:14 +08:00
|
|
|
// For accessor stubs, go back to the interface.
|
|
|
|
if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container))
|
|
|
|
if (isSynthesizedAccessorStub())
|
|
|
|
Container = ImplDecl->getClassInterface();
|
|
|
|
|
2012-10-11 00:42:54 +08:00
|
|
|
bool IsGetter = (NumArgs == 0);
|
2016-03-12 05:14:40 +08:00
|
|
|
bool IsInstance = isInstanceMethod();
|
2012-10-11 00:42:54 +08:00
|
|
|
|
Stop back-patching 'readonly' Objective-C properties with 'readwrite' ones.
A 'readonly' Objective-C property declared in the primary class can
effectively be shadowed by a 'readwrite' property declared within an
extension of that class, so long as the types and attributes of the
two property declarations are compatible.
Previously, this functionality was implemented by back-patching the
original 'readonly' property to make it 'readwrite', destroying source
information and causing some hideously redundant, incorrect
code. Simplify the implementation to express how this should actually
be modeled: as a separate property declaration in the extension that
shadows (via the name lookup rules) the declaration in the primary
class. While here, correct some broken Fix-Its, eliminate a pile of
redundant code, clean up the ARC migrator's handling of properties
declared in extensions, and fix debug info's naming of methods that
come from categories.
A wonderous side effect of doing this write is that it eliminates the
"AddedObjCPropertyInClassExtension" method from the AST mutation
listener, which in turn eliminates the last place where we rewrite
entire declarations in a chained PCH file or a module file. This
change (which fixes rdar://problem/18475765) will allow us to
eliminate the rewritten-decls logic from the serialization library,
and fixes a crash (rdar://problem/23247794) illustrated by the
test/PCH/chain-categories.m example.
llvm-svn: 251874
2015-11-03 09:15:46 +08:00
|
|
|
/// Local function that attempts to find a matching property within the
|
|
|
|
/// given Objective-C container.
|
|
|
|
auto findMatchingProperty =
|
|
|
|
[&](const ObjCContainerDecl *Container) -> const ObjCPropertyDecl * {
|
2016-03-12 05:14:40 +08:00
|
|
|
if (IsInstance) {
|
|
|
|
for (const auto *I : Container->instance_properties()) {
|
|
|
|
Selector NextSel = IsGetter ? I->getGetterName()
|
|
|
|
: I->getSetterName();
|
|
|
|
if (NextSel == Sel)
|
|
|
|
return I;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (const auto *I : Container->class_properties()) {
|
|
|
|
Selector NextSel = IsGetter ? I->getGetterName()
|
|
|
|
: I->getSetterName();
|
|
|
|
if (NextSel == Sel)
|
|
|
|
return I;
|
|
|
|
}
|
Stop back-patching 'readonly' Objective-C properties with 'readwrite' ones.
A 'readonly' Objective-C property declared in the primary class can
effectively be shadowed by a 'readwrite' property declared within an
extension of that class, so long as the types and attributes of the
two property declarations are compatible.
Previously, this functionality was implemented by back-patching the
original 'readonly' property to make it 'readwrite', destroying source
information and causing some hideously redundant, incorrect
code. Simplify the implementation to express how this should actually
be modeled: as a separate property declaration in the extension that
shadows (via the name lookup rules) the declaration in the primary
class. While here, correct some broken Fix-Its, eliminate a pile of
redundant code, clean up the ARC migrator's handling of properties
declared in extensions, and fix debug info's naming of methods that
come from categories.
A wonderous side effect of doing this write is that it eliminates the
"AddedObjCPropertyInClassExtension" method from the AST mutation
listener, which in turn eliminates the last place where we rewrite
entire declarations in a chained PCH file or a module file. This
change (which fixes rdar://problem/18475765) will allow us to
eliminate the rewritten-decls logic from the serialization library,
and fixes a crash (rdar://problem/23247794) illustrated by the
test/PCH/chain-categories.m example.
llvm-svn: 251874
2015-11-03 09:15:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Look in the container we were given.
|
|
|
|
if (const auto *Found = findMatchingProperty(Container))
|
|
|
|
return Found;
|
|
|
|
|
|
|
|
// If we're in a category or extension, look in the main class.
|
|
|
|
const ObjCInterfaceDecl *ClassDecl = nullptr;
|
|
|
|
if (const auto *Category = dyn_cast<ObjCCategoryDecl>(Container)) {
|
|
|
|
ClassDecl = Category->getClassInterface();
|
|
|
|
if (const auto *Found = findMatchingProperty(ClassDecl))
|
|
|
|
return Found;
|
|
|
|
} else {
|
|
|
|
// Determine whether the container is a class.
|
2020-03-12 23:36:33 +08:00
|
|
|
ClassDecl = cast<ObjCInterfaceDecl>(Container);
|
Stop back-patching 'readonly' Objective-C properties with 'readwrite' ones.
A 'readonly' Objective-C property declared in the primary class can
effectively be shadowed by a 'readwrite' property declared within an
extension of that class, so long as the types and attributes of the
two property declarations are compatible.
Previously, this functionality was implemented by back-patching the
original 'readonly' property to make it 'readwrite', destroying source
information and causing some hideously redundant, incorrect
code. Simplify the implementation to express how this should actually
be modeled: as a separate property declaration in the extension that
shadows (via the name lookup rules) the declaration in the primary
class. While here, correct some broken Fix-Its, eliminate a pile of
redundant code, clean up the ARC migrator's handling of properties
declared in extensions, and fix debug info's naming of methods that
come from categories.
A wonderous side effect of doing this write is that it eliminates the
"AddedObjCPropertyInClassExtension" method from the AST mutation
listener, which in turn eliminates the last place where we rewrite
entire declarations in a chained PCH file or a module file. This
change (which fixes rdar://problem/18475765) will allow us to
eliminate the rewritten-decls logic from the serialization library,
and fixes a crash (rdar://problem/23247794) illustrated by the
test/PCH/chain-categories.m example.
llvm-svn: 251874
2015-11-03 09:15:46 +08:00
|
|
|
}
|
2020-03-12 23:36:33 +08:00
|
|
|
assert(ClassDecl && "Failed to find main class");
|
Stop back-patching 'readonly' Objective-C properties with 'readwrite' ones.
A 'readonly' Objective-C property declared in the primary class can
effectively be shadowed by a 'readwrite' property declared within an
extension of that class, so long as the types and attributes of the
two property declarations are compatible.
Previously, this functionality was implemented by back-patching the
original 'readonly' property to make it 'readwrite', destroying source
information and causing some hideously redundant, incorrect
code. Simplify the implementation to express how this should actually
be modeled: as a separate property declaration in the extension that
shadows (via the name lookup rules) the declaration in the primary
class. While here, correct some broken Fix-Its, eliminate a pile of
redundant code, clean up the ARC migrator's handling of properties
declared in extensions, and fix debug info's naming of methods that
come from categories.
A wonderous side effect of doing this write is that it eliminates the
"AddedObjCPropertyInClassExtension" method from the AST mutation
listener, which in turn eliminates the last place where we rewrite
entire declarations in a chained PCH file or a module file. This
change (which fixes rdar://problem/18475765) will allow us to
eliminate the rewritten-decls logic from the serialization library,
and fixes a crash (rdar://problem/23247794) illustrated by the
test/PCH/chain-categories.m example.
llvm-svn: 251874
2015-11-03 09:15:46 +08:00
|
|
|
|
|
|
|
// If we have a class, check its visible extensions.
|
2020-03-12 23:36:33 +08:00
|
|
|
for (const auto *Ext : ClassDecl->visible_extensions()) {
|
|
|
|
if (Ext == Container)
|
|
|
|
continue;
|
|
|
|
if (const auto *Found = findMatchingProperty(Ext))
|
|
|
|
return Found;
|
2012-10-11 00:42:54 +08:00
|
|
|
}
|
|
|
|
|
2019-11-05 06:28:14 +08:00
|
|
|
assert(isSynthesizedAccessorStub() && "expected an accessor stub");
|
2020-03-12 23:36:33 +08:00
|
|
|
|
2019-11-05 06:28:14 +08:00
|
|
|
for (const auto *Cat : ClassDecl->known_categories()) {
|
|
|
|
if (Cat == Container)
|
|
|
|
continue;
|
|
|
|
if (const auto *Found = findMatchingProperty(Cat))
|
|
|
|
return Found;
|
|
|
|
}
|
|
|
|
|
2012-10-11 00:42:54 +08:00
|
|
|
llvm_unreachable("Marked as a property accessor but no property found!");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CheckOverrides)
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2012-10-11 00:42:54 +08:00
|
|
|
|
2017-11-23 05:32:07 +08:00
|
|
|
using OverridesTy = SmallVector<const ObjCMethodDecl *, 8>;
|
|
|
|
|
2012-10-11 00:42:54 +08:00
|
|
|
OverridesTy Overrides;
|
|
|
|
getOverriddenMethods(Overrides);
|
2018-04-10 06:14:10 +08:00
|
|
|
for (const auto *Override : Overrides)
|
|
|
|
if (const ObjCPropertyDecl *Prop = Override->findPropertyDecl(false))
|
2012-10-11 00:42:54 +08:00
|
|
|
return Prop;
|
|
|
|
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2012-10-11 00:42:54 +08:00
|
|
|
}
|
|
|
|
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ObjCTypeParamDecl
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-11-23 05:32:07 +08:00
|
|
|
void ObjCTypeParamDecl::anchor() {}
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
|
|
|
|
ObjCTypeParamDecl *ObjCTypeParamDecl::Create(ASTContext &ctx, DeclContext *dc,
|
2015-07-07 11:58:54 +08:00
|
|
|
ObjCTypeParamVariance variance,
|
|
|
|
SourceLocation varianceLoc,
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 11:57:53 +08:00
|
|
|
unsigned index,
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
SourceLocation nameLoc,
|
|
|
|
IdentifierInfo *name,
|
|
|
|
SourceLocation colonLoc,
|
|
|
|
TypeSourceInfo *boundInfo) {
|
2016-09-14 01:41:05 +08:00
|
|
|
auto *TPDecl =
|
|
|
|
new (ctx, dc) ObjCTypeParamDecl(ctx, dc, variance, varianceLoc, index,
|
|
|
|
nameLoc, name, colonLoc, boundInfo);
|
|
|
|
QualType TPType = ctx.getObjCTypeParamType(TPDecl, {});
|
|
|
|
TPDecl->setTypeForDecl(TPType.getTypePtr());
|
|
|
|
return TPDecl;
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ObjCTypeParamDecl *ObjCTypeParamDecl::CreateDeserialized(ASTContext &ctx,
|
|
|
|
unsigned ID) {
|
2015-07-07 11:58:54 +08:00
|
|
|
return new (ctx, ID) ObjCTypeParamDecl(ctx, nullptr,
|
|
|
|
ObjCTypeParamVariance::Invariant,
|
|
|
|
SourceLocation(), 0, SourceLocation(),
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
nullptr, SourceLocation(), nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceRange ObjCTypeParamDecl::getSourceRange() const {
|
2015-07-07 11:58:54 +08:00
|
|
|
SourceLocation startLoc = VarianceLoc;
|
|
|
|
if (startLoc.isInvalid())
|
|
|
|
startLoc = getLocation();
|
|
|
|
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
if (hasExplicitBound()) {
|
2015-07-07 11:58:54 +08:00
|
|
|
return SourceRange(startLoc,
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
getTypeSourceInfo()->getTypeLoc().getEndLoc());
|
|
|
|
}
|
|
|
|
|
2015-07-07 11:58:54 +08:00
|
|
|
return SourceRange(startLoc);
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ObjCTypeParamList
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
ObjCTypeParamList::ObjCTypeParamList(SourceLocation lAngleLoc,
|
|
|
|
ArrayRef<ObjCTypeParamDecl *> typeParams,
|
|
|
|
SourceLocation rAngleLoc)
|
2021-01-12 18:22:35 +08:00
|
|
|
: Brackets(lAngleLoc, rAngleLoc), NumParams(typeParams.size()) {
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
std::copy(typeParams.begin(), typeParams.end(), begin());
|
|
|
|
}
|
|
|
|
|
|
|
|
ObjCTypeParamList *ObjCTypeParamList::create(
|
|
|
|
ASTContext &ctx,
|
|
|
|
SourceLocation lAngleLoc,
|
|
|
|
ArrayRef<ObjCTypeParamDecl *> typeParams,
|
|
|
|
SourceLocation rAngleLoc) {
|
2015-12-30 06:13:13 +08:00
|
|
|
void *mem =
|
|
|
|
ctx.Allocate(totalSizeToAlloc<ObjCTypeParamDecl *>(typeParams.size()),
|
2016-10-20 22:27:22 +08:00
|
|
|
alignof(ObjCTypeParamList));
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
return new (mem) ObjCTypeParamList(lAngleLoc, typeParams, rAngleLoc);
|
|
|
|
}
|
|
|
|
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 11:57:53 +08:00
|
|
|
void ObjCTypeParamList::gatherDefaultTypeArgs(
|
|
|
|
SmallVectorImpl<QualType> &typeArgs) const {
|
|
|
|
typeArgs.reserve(size());
|
|
|
|
for (auto typeParam : *this)
|
|
|
|
typeArgs.push_back(typeParam->getUnderlyingType());
|
|
|
|
}
|
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ObjCInterfaceDecl
|
|
|
|
//===----------------------------------------------------------------------===//
|
2009-02-20 14:03:09 +08:00
|
|
|
|
2012-01-18 02:09:05 +08:00
|
|
|
ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C,
|
2009-01-09 08:49:46 +08:00
|
|
|
DeclContext *DC,
|
2008-04-04 14:12:32 +08:00
|
|
|
SourceLocation atLoc,
|
2009-09-09 23:08:12 +08:00
|
|
|
IdentifierInfo *Id,
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
ObjCTypeParamList *typeParamList,
|
2011-12-16 11:12:41 +08:00
|
|
|
ObjCInterfaceDecl *PrevDecl,
|
2008-04-12 03:35:35 +08:00
|
|
|
SourceLocation ClassLoc,
|
2011-12-16 04:29:51 +08:00
|
|
|
bool isInternal){
|
2018-04-10 06:14:10 +08:00
|
|
|
auto *Result = new (C, DC)
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
ObjCInterfaceDecl(C, DC, atLoc, Id, typeParamList, ClassLoc, PrevDecl,
|
|
|
|
isInternal);
|
Ensure that type definitions present in just-loaded modules are
visible.
The basic problem here is that a given translation unit can use
forward declarations to form pointers to a given type, say,
class X;
X *x;
and then import a module that includes a definition of X:
import XDef;
We will then fail when attempting to access a member of X, e.g.,
x->method()
because the AST reader did not know to look for a default of a class
named X within the new module.
This implementation is a bit of a C-centric hack, because the only
definitions that can have this property are enums, structs, unions,
Objective-C classes, and Objective-C protocols, and all of those are
either visible at the top-level or can't be defined later. Hence, we
can use the out-of-date-ness of the name and the identifier-update
mechanism to force the update.
In C++, we will not be so lucky, and will need a more advanced
solution, because the definitions could be in namespaces defined in
two different modules, e.g.,
// module 1
namespace N { struct X; }
// module 2
namespace N { struct X { /* ... */ }; }
One possible implementation here is for C++ to extend the information
associated with each identifier table to include the declaration IDs
of any definitions associated with that name, regardless of
context. We would have to eagerly load those definitions.
llvm-svn: 174794
2013-02-09 09:35:03 +08:00
|
|
|
Result->Data.setInt(!C.getLangOpts().Modules);
|
2011-12-16 11:12:41 +08:00
|
|
|
C.getObjCInterfaceType(Result, PrevDecl);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
If a declaration is loaded, and then a module import adds a redeclaration, then
ensure that querying the first declaration for its most recent declaration
checks for redeclarations from the imported module.
This works as follows:
* The 'most recent' pointer on a canonical declaration grows a pointer to the
external AST source and a generation number (space- and time-optimized for
the case where there is no external source).
* Each time the 'most recent' pointer is queried, if it has an external source,
we check whether it's up to date, and update it if not.
* The ancillary data stored on the canonical declaration is allocated lazily
to avoid filling it in for declarations that end up being non-canonical.
We'll still perform a redundant (ASTContext) allocation if someone asks for
the most recent declaration from a decl before setPreviousDecl is called,
but such cases are probably all bugs, and are now easy to find.
Some finessing is still in order here -- in particular, we use a very general
mechanism for handling the DefinitionData pointer on CXXRecordData, and a more
targeted approach would be more compact.
Also, the MayHaveOutOfDateDef mechanism should now be expunged, since it was
addressing only a corner of the full problem space here. That's not covered
by this patch.
Early performance benchmarks show that this makes no measurable difference to
Clang performance without modules enabled (and fixes a major correctness issue
with modules enabled). I'll revert if a full performance comparison shows any
problems.
llvm-svn: 209046
2014-05-17 07:01:30 +08:00
|
|
|
ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C,
|
2012-01-06 05:55:30 +08:00
|
|
|
unsigned ID) {
|
2018-04-10 06:14:10 +08:00
|
|
|
auto *Result = new (C, ID)
|
|
|
|
ObjCInterfaceDecl(C, nullptr, SourceLocation(), nullptr, nullptr,
|
|
|
|
SourceLocation(), nullptr, false);
|
Ensure that type definitions present in just-loaded modules are
visible.
The basic problem here is that a given translation unit can use
forward declarations to form pointers to a given type, say,
class X;
X *x;
and then import a module that includes a definition of X:
import XDef;
We will then fail when attempting to access a member of X, e.g.,
x->method()
because the AST reader did not know to look for a default of a class
named X within the new module.
This implementation is a bit of a C-centric hack, because the only
definitions that can have this property are enums, structs, unions,
Objective-C classes, and Objective-C protocols, and all of those are
either visible at the top-level or can't be defined later. Hence, we
can use the out-of-date-ness of the name and the identifier-update
mechanism to force the update.
In C++, we will not be so lucky, and will need a more advanced
solution, because the definitions could be in namespaces defined in
two different modules, e.g.,
// module 1
namespace N { struct X; }
// module 2
namespace N { struct X { /* ... */ }; }
One possible implementation here is for C++ to extend the information
associated with each identifier table to include the declaration IDs
of any definitions associated with that name, regardless of
context. We would have to eagerly load those definitions.
llvm-svn: 174794
2013-02-09 09:35:03 +08:00
|
|
|
Result->Data.setInt(!C.getLangOpts().Modules);
|
|
|
|
return Result;
|
2008-03-16 09:15:50 +08:00
|
|
|
}
|
2008-03-16 08:49:28 +08:00
|
|
|
|
If a declaration is loaded, and then a module import adds a redeclaration, then
ensure that querying the first declaration for its most recent declaration
checks for redeclarations from the imported module.
This works as follows:
* The 'most recent' pointer on a canonical declaration grows a pointer to the
external AST source and a generation number (space- and time-optimized for
the case where there is no external source).
* Each time the 'most recent' pointer is queried, if it has an external source,
we check whether it's up to date, and update it if not.
* The ancillary data stored on the canonical declaration is allocated lazily
to avoid filling it in for declarations that end up being non-canonical.
We'll still perform a redundant (ASTContext) allocation if someone asks for
the most recent declaration from a decl before setPreviousDecl is called,
but such cases are probably all bugs, and are now easy to find.
Some finessing is still in order here -- in particular, we use a very general
mechanism for handling the DefinitionData pointer on CXXRecordData, and a more
targeted approach would be more compact.
Also, the MayHaveOutOfDateDef mechanism should now be expunged, since it was
addressing only a corner of the full problem space here. That's not covered
by this patch.
Early performance benchmarks show that this makes no measurable difference to
Clang performance without modules enabled (and fixes a major correctness issue
with modules enabled). I'll revert if a full performance comparison shows any
problems.
llvm-svn: 209046
2014-05-17 07:01:30 +08:00
|
|
|
ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation AtLoc, IdentifierInfo *Id,
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
ObjCTypeParamList *typeParamList,
|
If a declaration is loaded, and then a module import adds a redeclaration, then
ensure that querying the first declaration for its most recent declaration
checks for redeclarations from the imported module.
This works as follows:
* The 'most recent' pointer on a canonical declaration grows a pointer to the
external AST source and a generation number (space- and time-optimized for
the case where there is no external source).
* Each time the 'most recent' pointer is queried, if it has an external source,
we check whether it's up to date, and update it if not.
* The ancillary data stored on the canonical declaration is allocated lazily
to avoid filling it in for declarations that end up being non-canonical.
We'll still perform a redundant (ASTContext) allocation if someone asks for
the most recent declaration from a decl before setPreviousDecl is called,
but such cases are probably all bugs, and are now easy to find.
Some finessing is still in order here -- in particular, we use a very general
mechanism for handling the DefinitionData pointer on CXXRecordData, and a more
targeted approach would be more compact.
Also, the MayHaveOutOfDateDef mechanism should now be expunged, since it was
addressing only a corner of the full problem space here. That's not covered
by this patch.
Early performance benchmarks show that this makes no measurable difference to
Clang performance without modules enabled (and fixes a major correctness issue
with modules enabled). I'll revert if a full performance comparison shows any
problems.
llvm-svn: 209046
2014-05-17 07:01:30 +08:00
|
|
|
SourceLocation CLoc,
|
|
|
|
ObjCInterfaceDecl *PrevDecl,
|
|
|
|
bool IsInternal)
|
|
|
|
: ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, AtLoc),
|
2017-11-23 05:32:07 +08:00
|
|
|
redeclarable_base(C) {
|
2013-10-17 23:37:26 +08:00
|
|
|
setPreviousDecl(PrevDecl);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-17 06:37:11 +08:00
|
|
|
// Copy the 'data' pointer over.
|
|
|
|
if (PrevDecl)
|
|
|
|
Data = PrevDecl->Data;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
If a declaration is loaded, and then a module import adds a redeclaration, then
ensure that querying the first declaration for its most recent declaration
checks for redeclarations from the imported module.
This works as follows:
* The 'most recent' pointer on a canonical declaration grows a pointer to the
external AST source and a generation number (space- and time-optimized for
the case where there is no external source).
* Each time the 'most recent' pointer is queried, if it has an external source,
we check whether it's up to date, and update it if not.
* The ancillary data stored on the canonical declaration is allocated lazily
to avoid filling it in for declarations that end up being non-canonical.
We'll still perform a redundant (ASTContext) allocation if someone asks for
the most recent declaration from a decl before setPreviousDecl is called,
but such cases are probably all bugs, and are now easy to find.
Some finessing is still in order here -- in particular, we use a very general
mechanism for handling the DefinitionData pointer on CXXRecordData, and a more
targeted approach would be more compact.
Also, the MayHaveOutOfDateDef mechanism should now be expunged, since it was
addressing only a corner of the full problem space here. That's not covered
by this patch.
Early performance benchmarks show that this makes no measurable difference to
Clang performance without modules enabled (and fixes a major correctness issue
with modules enabled). I'll revert if a full performance comparison shows any
problems.
llvm-svn: 209046
2014-05-17 07:01:30 +08:00
|
|
|
setImplicit(IsInternal);
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
|
2015-07-07 14:20:12 +08:00
|
|
|
setTypeParamList(typeParamList);
|
2009-01-08 01:57:40 +08:00
|
|
|
}
|
|
|
|
|
2010-12-02 07:49:52 +08:00
|
|
|
void ObjCInterfaceDecl::LoadExternalDefinition() const {
|
2011-12-15 13:27:12 +08:00
|
|
|
assert(data().ExternallyCompleted && "Class is not externally completed");
|
|
|
|
data().ExternallyCompleted = false;
|
2010-12-02 07:49:52 +08:00
|
|
|
getASTContext().getExternalSource()->CompleteType(
|
|
|
|
const_cast<ObjCInterfaceDecl *>(this));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObjCInterfaceDecl::setExternallyCompleted() {
|
2018-07-31 03:24:48 +08:00
|
|
|
assert(getASTContext().getExternalSource() &&
|
2010-12-02 07:49:52 +08:00
|
|
|
"Class can't be externally completed without an external source");
|
2018-07-31 03:24:48 +08:00
|
|
|
assert(hasDefinition() &&
|
2010-12-02 07:49:52 +08:00
|
|
|
"Forward declarations can't be externally completed");
|
2011-12-15 13:27:12 +08:00
|
|
|
data().ExternallyCompleted = true;
|
2010-12-02 07:49:52 +08:00
|
|
|
}
|
|
|
|
|
2013-12-04 05:11:30 +08:00
|
|
|
void ObjCInterfaceDecl::setHasDesignatedInitializers() {
|
2014-03-12 02:56:18 +08:00
|
|
|
// Check for a complete definition and recover if not so.
|
|
|
|
if (!isThisDeclarationADefinition())
|
|
|
|
return;
|
2013-12-04 05:11:30 +08:00
|
|
|
data().HasDesignatedInitializers = true;
|
|
|
|
}
|
|
|
|
|
2013-12-04 05:11:49 +08:00
|
|
|
bool ObjCInterfaceDecl::hasDesignatedInitializers() const {
|
2014-03-12 02:56:18 +08:00
|
|
|
// Check for a complete definition and recover if not so.
|
|
|
|
if (!isThisDeclarationADefinition())
|
|
|
|
return false;
|
2013-12-04 05:11:49 +08:00
|
|
|
if (data().ExternallyCompleted)
|
|
|
|
LoadExternalDefinition();
|
|
|
|
|
|
|
|
return data().HasDesignatedInitializers;
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:16:04 +08:00
|
|
|
StringRef
|
|
|
|
ObjCInterfaceDecl::getObjCRuntimeNameAsString() const {
|
2018-04-10 06:14:10 +08:00
|
|
|
if (const auto *ObjCRTName = getAttr<ObjCRuntimeNameAttr>())
|
2014-07-17 03:44:34 +08:00
|
|
|
return ObjCRTName->getMetadataName();
|
|
|
|
|
|
|
|
return getName();
|
2014-07-17 00:16:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
StringRef
|
|
|
|
ObjCImplementationDecl::getObjCRuntimeNameAsString() const {
|
2014-07-17 03:44:34 +08:00
|
|
|
if (ObjCInterfaceDecl *ID =
|
|
|
|
const_cast<ObjCImplementationDecl*>(this)->getClassInterface())
|
|
|
|
return ID->getObjCRuntimeNameAsString();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2014-07-17 03:44:34 +08:00
|
|
|
return getName();
|
2014-07-17 00:16:04 +08:00
|
|
|
}
|
|
|
|
|
2009-07-21 08:05:53 +08:00
|
|
|
ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const {
|
2011-12-16 04:29:51 +08:00
|
|
|
if (const ObjCInterfaceDecl *Def = getDefinition()) {
|
|
|
|
if (data().ExternallyCompleted)
|
|
|
|
LoadExternalDefinition();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-16 04:29:51 +08:00
|
|
|
return getASTContext().getObjCImplementation(
|
|
|
|
const_cast<ObjCInterfaceDecl*>(Def));
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-15 13:27:12 +08:00
|
|
|
// FIXME: Should make sure no callers ever do this.
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2009-07-21 08:05:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) {
|
2011-12-16 04:29:51 +08:00
|
|
|
getASTContext().setObjCImplementation(getDefinition(), ImplD);
|
2009-07-21 08:05:53 +08:00
|
|
|
}
|
|
|
|
|
2013-02-14 06:50:36 +08:00
|
|
|
namespace {
|
2017-11-23 05:32:07 +08:00
|
|
|
|
|
|
|
struct SynthesizeIvarChunk {
|
|
|
|
uint64_t Size;
|
|
|
|
ObjCIvarDecl *Ivar;
|
|
|
|
|
|
|
|
SynthesizeIvarChunk(uint64_t size, ObjCIvarDecl *ivar)
|
2013-02-14 06:50:36 +08:00
|
|
|
: Size(size), Ivar(ivar) {}
|
2017-11-23 05:32:07 +08:00
|
|
|
};
|
2013-02-14 06:50:36 +08:00
|
|
|
|
2017-11-23 05:32:07 +08:00
|
|
|
bool operator<(const SynthesizeIvarChunk & LHS,
|
|
|
|
const SynthesizeIvarChunk &RHS) {
|
|
|
|
return LHS.Size < RHS.Size;
|
2015-06-23 07:07:51 +08:00
|
|
|
}
|
2013-02-14 06:50:36 +08:00
|
|
|
|
2017-11-23 05:32:07 +08:00
|
|
|
} // namespace
|
|
|
|
|
2010-08-21 05:21:08 +08:00
|
|
|
/// all_declared_ivar_begin - return first ivar declared in this class,
|
|
|
|
/// its extensions and its implementation. Lazily build the list on first
|
|
|
|
/// access.
|
2013-03-07 06:03:30 +08:00
|
|
|
///
|
|
|
|
/// Caveat: The list returned by this method reflects the current
|
|
|
|
/// state of the parser. The cache will be updated for every ivar
|
|
|
|
/// added by an extension or the implementation when they are
|
|
|
|
/// encountered.
|
|
|
|
/// See also ObjCIvarDecl::Create().
|
2010-08-21 05:21:08 +08:00
|
|
|
ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
|
2011-12-15 13:27:12 +08:00
|
|
|
// FIXME: Should make sure no callers ever do this.
|
|
|
|
if (!hasDefinition())
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
ObjCIvarDecl *curIvar = nullptr;
|
2013-03-07 06:03:30 +08:00
|
|
|
if (!data().IvarList) {
|
|
|
|
if (!ivar_empty()) {
|
|
|
|
ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end();
|
|
|
|
data().IvarList = *I; ++I;
|
|
|
|
for (curIvar = data().IvarList; I != E; curIvar = *I, ++I)
|
|
|
|
curIvar->setNextIvar(*I);
|
|
|
|
}
|
2013-01-17 07:00:23 +08:00
|
|
|
|
2014-03-14 05:57:01 +08:00
|
|
|
for (const auto *Ext : known_extensions()) {
|
2013-03-07 06:03:30 +08:00
|
|
|
if (!Ext->ivar_empty()) {
|
|
|
|
ObjCCategoryDecl::ivar_iterator
|
|
|
|
I = Ext->ivar_begin(),
|
|
|
|
E = Ext->ivar_end();
|
|
|
|
if (!data().IvarList) {
|
|
|
|
data().IvarList = *I; ++I;
|
|
|
|
curIvar = data().IvarList;
|
|
|
|
}
|
|
|
|
for ( ;I != E; curIvar = *I, ++I)
|
|
|
|
curIvar->setNextIvar(*I);
|
2010-08-21 05:21:08 +08:00
|
|
|
}
|
|
|
|
}
|
2013-03-07 06:03:30 +08:00
|
|
|
data().IvarListMissingImplementation = true;
|
2010-08-21 05:21:08 +08:00
|
|
|
}
|
2013-03-07 06:03:30 +08:00
|
|
|
|
|
|
|
// cached and complete!
|
|
|
|
if (!data().IvarListMissingImplementation)
|
|
|
|
return data().IvarList;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-08-21 05:21:08 +08:00
|
|
|
if (ObjCImplementationDecl *ImplDecl = getImplementation()) {
|
2013-03-07 06:03:30 +08:00
|
|
|
data().IvarListMissingImplementation = false;
|
2010-08-21 05:21:08 +08:00
|
|
|
if (!ImplDecl->ivar_empty()) {
|
2013-02-14 06:50:36 +08:00
|
|
|
SmallVector<SynthesizeIvarChunk, 16> layout;
|
2014-03-14 23:16:45 +08:00
|
|
|
for (auto *IV : ImplDecl->ivars()) {
|
2013-02-14 06:50:36 +08:00
|
|
|
if (IV->getSynthesize() && !IV->isInvalidDecl()) {
|
|
|
|
layout.push_back(SynthesizeIvarChunk(
|
|
|
|
IV->getASTContext().getTypeSize(IV->getType()), IV));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!data().IvarList)
|
2014-03-14 23:16:45 +08:00
|
|
|
data().IvarList = IV;
|
2013-02-14 06:50:36 +08:00
|
|
|
else
|
2014-03-14 23:16:45 +08:00
|
|
|
curIvar->setNextIvar(IV);
|
|
|
|
curIvar = IV;
|
2013-02-14 06:50:36 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-02-14 06:50:36 +08:00
|
|
|
if (!layout.empty()) {
|
|
|
|
// Order synthesized ivars by their size.
|
2019-04-24 22:43:05 +08:00
|
|
|
llvm::stable_sort(layout);
|
2013-02-14 06:50:36 +08:00
|
|
|
unsigned Ix = 0, EIx = layout.size();
|
|
|
|
if (!data().IvarList) {
|
|
|
|
data().IvarList = layout[0].Ivar; Ix++;
|
|
|
|
curIvar = data().IvarList;
|
|
|
|
}
|
|
|
|
for ( ; Ix != EIx; curIvar = layout[Ix].Ivar, Ix++)
|
|
|
|
curIvar->setNextIvar(layout[Ix].Ivar);
|
2010-08-21 05:21:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-12-15 13:27:12 +08:00
|
|
|
return data().IvarList;
|
2010-08-21 05:21:08 +08:00
|
|
|
}
|
2008-06-07 00:45:15 +08:00
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
/// FindCategoryDeclaration - Finds category declaration in the list of
|
|
|
|
/// categories for this class and returns it. Name of the category is passed
|
|
|
|
/// in 'CategoryId'. If category not found, return 0;
|
|
|
|
///
|
|
|
|
ObjCCategoryDecl *
|
|
|
|
ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const {
|
2012-03-03 03:14:29 +08:00
|
|
|
// FIXME: Should make sure no callers ever do this.
|
|
|
|
if (!hasDefinition())
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2012-03-03 03:14:29 +08:00
|
|
|
|
2011-12-15 13:27:12 +08:00
|
|
|
if (data().ExternallyCompleted)
|
2010-12-02 07:49:52 +08:00
|
|
|
LoadExternalDefinition();
|
|
|
|
|
2014-03-14 05:23:55 +08:00
|
|
|
for (auto *Cat : visible_categories())
|
2013-01-17 07:00:23 +08:00
|
|
|
if (Cat->getIdentifier() == CategoryId)
|
2014-03-14 05:23:55 +08:00
|
|
|
return Cat;
|
2014-05-12 13:36:57 +08:00
|
|
|
|
|
|
|
return nullptr;
|
2009-02-21 04:59:54 +08:00
|
|
|
}
|
|
|
|
|
2009-07-21 08:06:20 +08:00
|
|
|
ObjCMethodDecl *
|
|
|
|
ObjCInterfaceDecl::getCategoryInstanceMethod(Selector Sel) const {
|
2014-03-14 05:23:55 +08:00
|
|
|
for (const auto *Cat : visible_categories()) {
|
2013-01-17 07:00:23 +08:00
|
|
|
if (ObjCCategoryImplDecl *Impl = Cat->getImplementation())
|
2009-07-21 08:06:20 +08:00
|
|
|
if (ObjCMethodDecl *MD = Impl->getInstanceMethod(Sel))
|
|
|
|
return MD;
|
2013-01-17 07:00:23 +08:00
|
|
|
}
|
|
|
|
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2009-07-21 08:06:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ObjCMethodDecl *ObjCInterfaceDecl::getCategoryClassMethod(Selector Sel) const {
|
2014-03-14 05:23:55 +08:00
|
|
|
for (const auto *Cat : visible_categories()) {
|
2013-01-17 07:00:23 +08:00
|
|
|
if (ObjCCategoryImplDecl *Impl = Cat->getImplementation())
|
2009-07-21 08:06:20 +08:00
|
|
|
if (ObjCMethodDecl *MD = Impl->getClassMethod(Sel))
|
|
|
|
return MD;
|
2013-01-17 07:00:23 +08:00
|
|
|
}
|
2014-05-12 13:36:57 +08:00
|
|
|
|
|
|
|
return nullptr;
|
2009-07-21 08:06:20 +08:00
|
|
|
}
|
|
|
|
|
2009-08-12 06:02:25 +08:00
|
|
|
/// ClassImplementsProtocol - Checks that 'lProto' protocol
|
|
|
|
/// has been implemented in IDecl class, its super class or categories (if
|
|
|
|
/// lookupCategory is true).
|
|
|
|
bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto,
|
|
|
|
bool lookupCategory,
|
|
|
|
bool RHSIsQualifiedID) {
|
2011-12-15 13:27:12 +08:00
|
|
|
if (!hasDefinition())
|
|
|
|
return false;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-08-12 06:02:25 +08:00
|
|
|
ObjCInterfaceDecl *IDecl = this;
|
|
|
|
// 1st, look up the class.
|
2014-03-14 04:29:09 +08:00
|
|
|
for (auto *PI : IDecl->protocols()){
|
|
|
|
if (getASTContext().ProtocolCompatibleWithProtocol(lProto, PI))
|
2009-08-12 06:02:25 +08:00
|
|
|
return true;
|
|
|
|
// This is dubious and is added to be compatible with gcc. In gcc, it is
|
|
|
|
// also allowed assigning a protocol-qualified 'id' type to a LHS object
|
|
|
|
// when protocol in qualified LHS is in list of protocols in the rhs 'id'
|
|
|
|
// object. This IMO, should be a bug.
|
|
|
|
// FIXME: Treat this as an extension, and flag this as an error when GCC
|
|
|
|
// extensions are not enabled.
|
2009-09-09 23:08:12 +08:00
|
|
|
if (RHSIsQualifiedID &&
|
2014-03-14 04:29:09 +08:00
|
|
|
getASTContext().ProtocolCompatibleWithProtocol(PI, lProto))
|
2009-08-12 06:02:25 +08:00
|
|
|
return true;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-12 06:02:25 +08:00
|
|
|
// 2nd, look up the category.
|
|
|
|
if (lookupCategory)
|
2014-03-14 05:23:55 +08:00
|
|
|
for (const auto *Cat : visible_categories()) {
|
2014-03-14 20:55:57 +08:00
|
|
|
for (auto *PI : Cat->protocols())
|
|
|
|
if (getASTContext().ProtocolCompatibleWithProtocol(lProto, PI))
|
2009-08-12 06:02:25 +08:00
|
|
|
return true;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-12 06:02:25 +08:00
|
|
|
// 3rd, look up the super class(s)
|
|
|
|
if (IDecl->getSuperClass())
|
|
|
|
return
|
|
|
|
IDecl->getSuperClass()->ClassImplementsProtocol(lProto, lookupCategory,
|
|
|
|
RHSIsQualifiedID);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-12 06:02:25 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ObjCIvarDecl
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-11-23 05:32:07 +08:00
|
|
|
void ObjCIvarDecl::anchor() {}
|
2011-12-20 10:48:34 +08:00
|
|
|
|
2010-04-03 04:10:03 +08:00
|
|
|
ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC,
|
2011-03-08 16:55:46 +08:00
|
|
|
SourceLocation StartLoc,
|
|
|
|
SourceLocation IdLoc, IdentifierInfo *Id,
|
2009-12-07 10:54:59 +08:00
|
|
|
QualType T, TypeSourceInfo *TInfo,
|
2010-07-17 08:59:30 +08:00
|
|
|
AccessControl ac, Expr *BW,
|
2014-01-04 02:32:18 +08:00
|
|
|
bool synthesized) {
|
2010-04-03 04:10:03 +08:00
|
|
|
if (DC) {
|
|
|
|
// Ivar's can only appear in interfaces, implementations (via synthesized
|
|
|
|
// properties), and class extensions (via direct declaration, or synthesized
|
|
|
|
// properties).
|
|
|
|
//
|
|
|
|
// FIXME: This should really be asserting this:
|
|
|
|
// (isa<ObjCCategoryDecl>(DC) &&
|
|
|
|
// cast<ObjCCategoryDecl>(DC)->IsClassExtension()))
|
|
|
|
// but unfortunately we sometimes place ivars into non-class extension
|
|
|
|
// categories on error. This breaks an AST invariant, and should not be
|
|
|
|
// fixed.
|
|
|
|
assert((isa<ObjCInterfaceDecl>(DC) || isa<ObjCImplementationDecl>(DC) ||
|
|
|
|
isa<ObjCCategoryDecl>(DC)) &&
|
|
|
|
"Invalid ivar decl context!");
|
2010-08-21 05:21:08 +08:00
|
|
|
// Once a new ivar is created in any of class/class-extension/implementation
|
|
|
|
// decl contexts, the previously built IvarList must be rebuilt.
|
2018-04-10 06:14:10 +08:00
|
|
|
auto *ID = dyn_cast<ObjCInterfaceDecl>(DC);
|
2010-08-21 05:21:08 +08:00
|
|
|
if (!ID) {
|
2018-04-10 06:14:10 +08:00
|
|
|
if (auto *IM = dyn_cast<ObjCImplementationDecl>(DC))
|
2010-08-21 05:21:08 +08:00
|
|
|
ID = IM->getClassInterface();
|
2012-07-20 06:22:55 +08:00
|
|
|
else
|
|
|
|
ID = cast<ObjCCategoryDecl>(DC)->getClassInterface();
|
2010-08-21 05:21:08 +08:00
|
|
|
}
|
2014-05-12 13:36:57 +08:00
|
|
|
ID->setIvarList(nullptr);
|
2010-04-03 04:10:03 +08:00
|
|
|
}
|
|
|
|
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, DC) ObjCIvarDecl(DC, StartLoc, IdLoc, Id, T, TInfo, ac, BW,
|
2014-01-04 02:32:18 +08:00
|
|
|
synthesized);
|
2008-03-16 08:49:28 +08:00
|
|
|
}
|
|
|
|
|
2012-01-06 05:55:30 +08:00
|
|
|
ObjCIvarDecl *ObjCIvarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
2014-05-12 13:36:57 +08:00
|
|
|
return new (C, ID) ObjCIvarDecl(nullptr, SourceLocation(), SourceLocation(),
|
|
|
|
nullptr, QualType(), nullptr,
|
|
|
|
ObjCIvarDecl::None, nullptr, false);
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
2010-04-03 05:13:59 +08:00
|
|
|
const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const {
|
2018-04-10 06:14:10 +08:00
|
|
|
const auto *DC = cast<ObjCContainerDecl>(getDeclContext());
|
2010-04-03 05:13:59 +08:00
|
|
|
|
|
|
|
switch (DC->getKind()) {
|
|
|
|
default:
|
|
|
|
case ObjCCategoryImpl:
|
|
|
|
case ObjCProtocol:
|
2011-09-23 13:06:16 +08:00
|
|
|
llvm_unreachable("invalid ivar container!");
|
2010-04-03 05:13:59 +08:00
|
|
|
|
|
|
|
// Ivars can only appear in class extension categories.
|
|
|
|
case ObjCCategory: {
|
2018-04-10 06:14:10 +08:00
|
|
|
const auto *CD = cast<ObjCCategoryDecl>(DC);
|
2010-04-03 05:13:59 +08:00
|
|
|
assert(CD->IsClassExtension() && "invalid container for ivar!");
|
|
|
|
return CD->getClassInterface();
|
|
|
|
}
|
|
|
|
|
|
|
|
case ObjCImplementation:
|
|
|
|
return cast<ObjCImplementationDecl>(DC)->getClassInterface();
|
2008-08-20 11:26:33 +08:00
|
|
|
|
2010-04-03 05:13:59 +08:00
|
|
|
case ObjCInterface:
|
|
|
|
return cast<ObjCInterfaceDecl>(DC);
|
|
|
|
}
|
|
|
|
}
|
2009-02-21 04:59:54 +08:00
|
|
|
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 11:57:53 +08:00
|
|
|
QualType ObjCIvarDecl::getUsageType(QualType objectType) const {
|
|
|
|
return getType().substObjCMemberType(objectType, getDeclContext(),
|
|
|
|
ObjCSubstitutionContext::Property);
|
|
|
|
}
|
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ObjCAtDefsFieldDecl
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-11-23 05:32:07 +08:00
|
|
|
void ObjCAtDefsFieldDecl::anchor() {}
|
2011-12-20 10:48:34 +08:00
|
|
|
|
2008-08-20 11:26:33 +08:00
|
|
|
ObjCAtDefsFieldDecl
|
2011-03-08 16:55:46 +08:00
|
|
|
*ObjCAtDefsFieldDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation StartLoc, SourceLocation IdLoc,
|
2008-08-20 11:26:33 +08:00
|
|
|
IdentifierInfo *Id, QualType T, Expr *BW) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, DC) ObjCAtDefsFieldDecl(DC, StartLoc, IdLoc, Id, T, BW);
|
2008-08-20 11:26:33 +08:00
|
|
|
}
|
|
|
|
|
2013-11-22 17:01:48 +08:00
|
|
|
ObjCAtDefsFieldDecl *ObjCAtDefsFieldDecl::CreateDeserialized(ASTContext &C,
|
2012-01-06 05:55:30 +08:00
|
|
|
unsigned ID) {
|
2014-05-12 13:36:57 +08:00
|
|
|
return new (C, ID) ObjCAtDefsFieldDecl(nullptr, SourceLocation(),
|
|
|
|
SourceLocation(), nullptr, QualType(),
|
|
|
|
nullptr);
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ObjCProtocolDecl
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-11-23 05:32:07 +08:00
|
|
|
void ObjCProtocolDecl::anchor() {}
|
2011-12-20 10:48:34 +08:00
|
|
|
|
If a declaration is loaded, and then a module import adds a redeclaration, then
ensure that querying the first declaration for its most recent declaration
checks for redeclarations from the imported module.
This works as follows:
* The 'most recent' pointer on a canonical declaration grows a pointer to the
external AST source and a generation number (space- and time-optimized for
the case where there is no external source).
* Each time the 'most recent' pointer is queried, if it has an external source,
we check whether it's up to date, and update it if not.
* The ancillary data stored on the canonical declaration is allocated lazily
to avoid filling it in for declarations that end up being non-canonical.
We'll still perform a redundant (ASTContext) allocation if someone asks for
the most recent declaration from a decl before setPreviousDecl is called,
but such cases are probably all bugs, and are now easy to find.
Some finessing is still in order here -- in particular, we use a very general
mechanism for handling the DefinitionData pointer on CXXRecordData, and a more
targeted approach would be more compact.
Also, the MayHaveOutOfDateDef mechanism should now be expunged, since it was
addressing only a corner of the full problem space here. That's not covered
by this patch.
Early performance benchmarks show that this makes no measurable difference to
Clang performance without modules enabled (and fixes a major correctness issue
with modules enabled). I'll revert if a full performance comparison shows any
problems.
llvm-svn: 209046
2014-05-17 07:01:30 +08:00
|
|
|
ObjCProtocolDecl::ObjCProtocolDecl(ASTContext &C, DeclContext *DC,
|
|
|
|
IdentifierInfo *Id, SourceLocation nameLoc,
|
2012-01-02 04:30:41 +08:00
|
|
|
SourceLocation atStartLoc,
|
2012-01-02 06:06:18 +08:00
|
|
|
ObjCProtocolDecl *PrevDecl)
|
If a declaration is loaded, and then a module import adds a redeclaration, then
ensure that querying the first declaration for its most recent declaration
checks for redeclarations from the imported module.
This works as follows:
* The 'most recent' pointer on a canonical declaration grows a pointer to the
external AST source and a generation number (space- and time-optimized for
the case where there is no external source).
* Each time the 'most recent' pointer is queried, if it has an external source,
we check whether it's up to date, and update it if not.
* The ancillary data stored on the canonical declaration is allocated lazily
to avoid filling it in for declarations that end up being non-canonical.
We'll still perform a redundant (ASTContext) allocation if someone asks for
the most recent declaration from a decl before setPreviousDecl is called,
but such cases are probably all bugs, and are now easy to find.
Some finessing is still in order here -- in particular, we use a very general
mechanism for handling the DefinitionData pointer on CXXRecordData, and a more
targeted approach would be more compact.
Also, the MayHaveOutOfDateDef mechanism should now be expunged, since it was
addressing only a corner of the full problem space here. That's not covered
by this patch.
Early performance benchmarks show that this makes no measurable difference to
Clang performance without modules enabled (and fixes a major correctness issue
with modules enabled). I'll revert if a full performance comparison shows any
problems.
llvm-svn: 209046
2014-05-17 07:01:30 +08:00
|
|
|
: ObjCContainerDecl(ObjCProtocol, DC, Id, nameLoc, atStartLoc),
|
2017-11-23 05:32:07 +08:00
|
|
|
redeclarable_base(C) {
|
2013-10-17 23:37:26 +08:00
|
|
|
setPreviousDecl(PrevDecl);
|
2012-01-02 04:30:41 +08:00
|
|
|
if (PrevDecl)
|
|
|
|
Data = PrevDecl->Data;
|
|
|
|
}
|
|
|
|
|
2009-01-09 08:49:46 +08:00
|
|
|
ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC,
|
2011-10-04 12:48:02 +08:00
|
|
|
IdentifierInfo *Id,
|
|
|
|
SourceLocation nameLoc,
|
2011-10-18 03:48:06 +08:00
|
|
|
SourceLocation atStartLoc,
|
2012-01-02 06:06:18 +08:00
|
|
|
ObjCProtocolDecl *PrevDecl) {
|
2018-04-10 06:14:10 +08:00
|
|
|
auto *Result =
|
If a declaration is loaded, and then a module import adds a redeclaration, then
ensure that querying the first declaration for its most recent declaration
checks for redeclarations from the imported module.
This works as follows:
* The 'most recent' pointer on a canonical declaration grows a pointer to the
external AST source and a generation number (space- and time-optimized for
the case where there is no external source).
* Each time the 'most recent' pointer is queried, if it has an external source,
we check whether it's up to date, and update it if not.
* The ancillary data stored on the canonical declaration is allocated lazily
to avoid filling it in for declarations that end up being non-canonical.
We'll still perform a redundant (ASTContext) allocation if someone asks for
the most recent declaration from a decl before setPreviousDecl is called,
but such cases are probably all bugs, and are now easy to find.
Some finessing is still in order here -- in particular, we use a very general
mechanism for handling the DefinitionData pointer on CXXRecordData, and a more
targeted approach would be more compact.
Also, the MayHaveOutOfDateDef mechanism should now be expunged, since it was
addressing only a corner of the full problem space here. That's not covered
by this patch.
Early performance benchmarks show that this makes no measurable difference to
Clang performance without modules enabled (and fixes a major correctness issue
with modules enabled). I'll revert if a full performance comparison shows any
problems.
llvm-svn: 209046
2014-05-17 07:01:30 +08:00
|
|
|
new (C, DC) ObjCProtocolDecl(C, DC, Id, nameLoc, atStartLoc, PrevDecl);
|
Ensure that type definitions present in just-loaded modules are
visible.
The basic problem here is that a given translation unit can use
forward declarations to form pointers to a given type, say,
class X;
X *x;
and then import a module that includes a definition of X:
import XDef;
We will then fail when attempting to access a member of X, e.g.,
x->method()
because the AST reader did not know to look for a default of a class
named X within the new module.
This implementation is a bit of a C-centric hack, because the only
definitions that can have this property are enums, structs, unions,
Objective-C classes, and Objective-C protocols, and all of those are
either visible at the top-level or can't be defined later. Hence, we
can use the out-of-date-ness of the name and the identifier-update
mechanism to force the update.
In C++, we will not be so lucky, and will need a more advanced
solution, because the definitions could be in namespaces defined in
two different modules, e.g.,
// module 1
namespace N { struct X; }
// module 2
namespace N { struct X { /* ... */ }; }
One possible implementation here is for C++ to extend the information
associated with each identifier table to include the declaration IDs
of any definitions associated with that name, regardless of
context. We would have to eagerly load those definitions.
llvm-svn: 174794
2013-02-09 09:35:03 +08:00
|
|
|
Result->Data.setInt(!C.getLangOpts().Modules);
|
2012-01-02 04:30:41 +08:00
|
|
|
return Result;
|
2008-03-16 09:23:04 +08:00
|
|
|
}
|
|
|
|
|
2013-11-22 17:01:48 +08:00
|
|
|
ObjCProtocolDecl *ObjCProtocolDecl::CreateDeserialized(ASTContext &C,
|
2012-01-06 05:55:30 +08:00
|
|
|
unsigned ID) {
|
2013-11-22 17:01:48 +08:00
|
|
|
ObjCProtocolDecl *Result =
|
If a declaration is loaded, and then a module import adds a redeclaration, then
ensure that querying the first declaration for its most recent declaration
checks for redeclarations from the imported module.
This works as follows:
* The 'most recent' pointer on a canonical declaration grows a pointer to the
external AST source and a generation number (space- and time-optimized for
the case where there is no external source).
* Each time the 'most recent' pointer is queried, if it has an external source,
we check whether it's up to date, and update it if not.
* The ancillary data stored on the canonical declaration is allocated lazily
to avoid filling it in for declarations that end up being non-canonical.
We'll still perform a redundant (ASTContext) allocation if someone asks for
the most recent declaration from a decl before setPreviousDecl is called,
but such cases are probably all bugs, and are now easy to find.
Some finessing is still in order here -- in particular, we use a very general
mechanism for handling the DefinitionData pointer on CXXRecordData, and a more
targeted approach would be more compact.
Also, the MayHaveOutOfDateDef mechanism should now be expunged, since it was
addressing only a corner of the full problem space here. That's not covered
by this patch.
Early performance benchmarks show that this makes no measurable difference to
Clang performance without modules enabled (and fixes a major correctness issue
with modules enabled). I'll revert if a full performance comparison shows any
problems.
llvm-svn: 209046
2014-05-17 07:01:30 +08:00
|
|
|
new (C, ID) ObjCProtocolDecl(C, nullptr, nullptr, SourceLocation(),
|
2014-05-12 13:36:57 +08:00
|
|
|
SourceLocation(), nullptr);
|
Ensure that type definitions present in just-loaded modules are
visible.
The basic problem here is that a given translation unit can use
forward declarations to form pointers to a given type, say,
class X;
X *x;
and then import a module that includes a definition of X:
import XDef;
We will then fail when attempting to access a member of X, e.g.,
x->method()
because the AST reader did not know to look for a default of a class
named X within the new module.
This implementation is a bit of a C-centric hack, because the only
definitions that can have this property are enums, structs, unions,
Objective-C classes, and Objective-C protocols, and all of those are
either visible at the top-level or can't be defined later. Hence, we
can use the out-of-date-ness of the name and the identifier-update
mechanism to force the update.
In C++, we will not be so lucky, and will need a more advanced
solution, because the definitions could be in namespaces defined in
two different modules, e.g.,
// module 1
namespace N { struct X; }
// module 2
namespace N { struct X { /* ... */ }; }
One possible implementation here is for C++ to extend the information
associated with each identifier table to include the declaration IDs
of any definitions associated with that name, regardless of
context. We would have to eagerly load those definitions.
llvm-svn: 174794
2013-02-09 09:35:03 +08:00
|
|
|
Result->Data.setInt(!C.getLangOpts().Modules);
|
|
|
|
return Result;
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
2020-02-28 07:57:44 +08:00
|
|
|
bool ObjCProtocolDecl::isNonRuntimeProtocol() const {
|
|
|
|
return hasAttr<ObjCNonRuntimeProtocolAttr>();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObjCProtocolDecl::getImpliedProtocols(
|
|
|
|
llvm::DenseSet<const ObjCProtocolDecl *> &IPs) const {
|
|
|
|
std::queue<const ObjCProtocolDecl *> WorkQueue;
|
|
|
|
WorkQueue.push(this);
|
|
|
|
|
|
|
|
while (!WorkQueue.empty()) {
|
|
|
|
const auto *PD = WorkQueue.front();
|
|
|
|
WorkQueue.pop();
|
|
|
|
for (const auto *Parent : PD->protocols()) {
|
|
|
|
const auto *Can = Parent->getCanonicalDecl();
|
|
|
|
auto Result = IPs.insert(Can);
|
|
|
|
if (Result.second)
|
|
|
|
WorkQueue.push(Parent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-02 00:12:44 +08:00
|
|
|
ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) {
|
|
|
|
ObjCProtocolDecl *PDecl = this;
|
|
|
|
|
|
|
|
if (Name == getIdentifier())
|
|
|
|
return PDecl;
|
|
|
|
|
2014-03-14 06:58:06 +08:00
|
|
|
for (auto *I : protocols())
|
|
|
|
if ((PDecl = I->lookupProtocolNamed(Name)))
|
2009-03-02 00:12:44 +08:00
|
|
|
return PDecl;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2009-03-02 00:12:44 +08:00
|
|
|
}
|
|
|
|
|
2009-07-26 06:15:38 +08:00
|
|
|
// lookupMethod - Lookup a instance/class method in the protocol and protocols
|
2009-02-21 04:59:54 +08:00
|
|
|
// it inherited.
|
2009-07-26 06:15:38 +08:00
|
|
|
ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel,
|
|
|
|
bool isInstance) const {
|
2014-05-12 13:36:57 +08:00
|
|
|
ObjCMethodDecl *MethodDecl = nullptr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2013-01-17 08:38:46 +08:00
|
|
|
// If there is no definition or the definition is hidden, we don't find
|
|
|
|
// anything.
|
|
|
|
const ObjCProtocolDecl *Def = getDefinition();
|
2020-06-08 21:37:44 +08:00
|
|
|
if (!Def || !Def->isUnconditionallyVisible())
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2013-01-17 08:38:46 +08:00
|
|
|
|
2009-07-26 06:15:38 +08:00
|
|
|
if ((MethodDecl = getMethod(Sel, isInstance)))
|
2009-02-21 04:59:54 +08:00
|
|
|
return MethodDecl;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-03-14 06:58:06 +08:00
|
|
|
for (const auto *I : protocols())
|
|
|
|
if ((MethodDecl = I->lookupMethod(Sel, isInstance)))
|
2009-02-21 04:59:54 +08:00
|
|
|
return MethodDecl;
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2009-02-21 04:59:54 +08:00
|
|
|
}
|
2009-02-20 13:54:35 +08:00
|
|
|
|
2012-01-02 03:29:29 +08:00
|
|
|
void ObjCProtocolDecl::allocateDefinitionData() {
|
Ensure that type definitions present in just-loaded modules are
visible.
The basic problem here is that a given translation unit can use
forward declarations to form pointers to a given type, say,
class X;
X *x;
and then import a module that includes a definition of X:
import XDef;
We will then fail when attempting to access a member of X, e.g.,
x->method()
because the AST reader did not know to look for a default of a class
named X within the new module.
This implementation is a bit of a C-centric hack, because the only
definitions that can have this property are enums, structs, unions,
Objective-C classes, and Objective-C protocols, and all of those are
either visible at the top-level or can't be defined later. Hence, we
can use the out-of-date-ness of the name and the identifier-update
mechanism to force the update.
In C++, we will not be so lucky, and will need a more advanced
solution, because the definitions could be in namespaces defined in
two different modules, e.g.,
// module 1
namespace N { struct X; }
// module 2
namespace N { struct X { /* ... */ }; }
One possible implementation here is for C++ to extend the information
associated with each identifier table to include the declaration IDs
of any definitions associated with that name, regardless of
context. We would have to eagerly load those definitions.
llvm-svn: 174794
2013-02-09 09:35:03 +08:00
|
|
|
assert(!Data.getPointer() && "Protocol already has a definition!");
|
|
|
|
Data.setPointer(new (getASTContext()) DefinitionData);
|
|
|
|
Data.getPointer()->Definition = this;
|
2012-01-02 03:29:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ObjCProtocolDecl::startDefinition() {
|
|
|
|
allocateDefinitionData();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-01-02 03:51:50 +08:00
|
|
|
// Update all of the declarations with a pointer to the definition.
|
2018-04-10 06:14:10 +08:00
|
|
|
for (auto *RD : redecls())
|
2012-01-02 03:51:50 +08:00
|
|
|
RD->Data = this->Data;
|
2011-11-13 05:07:46 +08:00
|
|
|
}
|
|
|
|
|
2013-02-15 06:33:34 +08:00
|
|
|
void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM,
|
|
|
|
PropertyDeclOrder &PO) const {
|
2013-01-08 05:31:08 +08:00
|
|
|
if (const ObjCProtocolDecl *PDecl = getDefinition()) {
|
2016-01-29 07:36:05 +08:00
|
|
|
for (auto *Prop : PDecl->properties()) {
|
2013-01-08 05:31:08 +08:00
|
|
|
// Insert into PM if not there already.
|
2016-01-29 07:36:05 +08:00
|
|
|
PM.insert(std::make_pair(
|
|
|
|
std::make_pair(Prop->getIdentifier(), Prop->isClassProperty()),
|
|
|
|
Prop));
|
2013-02-15 06:33:34 +08:00
|
|
|
PO.push_back(Prop);
|
2013-01-08 05:31:08 +08:00
|
|
|
}
|
|
|
|
// Scan through protocol's protocols.
|
2014-03-14 06:58:06 +08:00
|
|
|
for (const auto *PI : PDecl->protocols())
|
|
|
|
PI->collectPropertiesToImplement(PM, PO);
|
2012-10-19 03:17:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-21 05:20:24 +08:00
|
|
|
void ObjCProtocolDecl::collectInheritedProtocolProperties(
|
2017-07-13 19:06:22 +08:00
|
|
|
const ObjCPropertyDecl *Property, ProtocolPropertySet &PS,
|
|
|
|
PropertyDeclOrder &PO) const {
|
2013-05-21 05:20:24 +08:00
|
|
|
if (const ObjCProtocolDecl *PDecl = getDefinition()) {
|
2017-07-13 19:06:22 +08:00
|
|
|
if (!PS.insert(PDecl).second)
|
|
|
|
return;
|
2016-01-28 04:00:32 +08:00
|
|
|
for (auto *Prop : PDecl->properties()) {
|
2013-05-21 05:20:24 +08:00
|
|
|
if (Prop == Property)
|
|
|
|
continue;
|
|
|
|
if (Prop->getIdentifier() == Property->getIdentifier()) {
|
2017-07-13 19:06:22 +08:00
|
|
|
PO.push_back(Prop);
|
|
|
|
return;
|
2013-05-21 05:20:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Scan through protocol's protocols which did not have a matching property.
|
2017-07-13 19:06:22 +08:00
|
|
|
for (const auto *PI : PDecl->protocols())
|
|
|
|
PI->collectInheritedProtocolProperties(Property, PS, PO);
|
2013-05-21 05:20:24 +08:00
|
|
|
}
|
|
|
|
}
|
2012-10-19 03:17:53 +08:00
|
|
|
|
2014-07-17 00:16:04 +08:00
|
|
|
StringRef
|
|
|
|
ObjCProtocolDecl::getObjCRuntimeNameAsString() const {
|
2018-04-10 06:14:10 +08:00
|
|
|
if (const auto *ObjCRTName = getAttr<ObjCRuntimeNameAttr>())
|
2014-07-17 03:44:34 +08:00
|
|
|
return ObjCRTName->getMetadataName();
|
|
|
|
|
|
|
|
return getName();
|
2014-07-17 00:16:04 +08:00
|
|
|
}
|
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ObjCCategoryDecl
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-11-23 05:32:07 +08:00
|
|
|
void ObjCCategoryDecl::anchor() {}
|
2011-12-20 10:48:34 +08:00
|
|
|
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
ObjCCategoryDecl::ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
|
2018-07-31 03:24:48 +08:00
|
|
|
SourceLocation ClassNameLoc,
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
SourceLocation CategoryNameLoc,
|
|
|
|
IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
|
|
|
|
ObjCTypeParamList *typeParamList,
|
|
|
|
SourceLocation IvarLBraceLoc,
|
|
|
|
SourceLocation IvarRBraceLoc)
|
2017-11-23 05:32:07 +08:00
|
|
|
: ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc),
|
|
|
|
ClassInterface(IDecl), CategoryNameLoc(CategoryNameLoc),
|
|
|
|
IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) {
|
2015-07-07 14:20:12 +08:00
|
|
|
setTypeParamList(typeParamList);
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
}
|
|
|
|
|
2009-01-09 08:49:46 +08:00
|
|
|
ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
|
2013-11-22 17:01:48 +08:00
|
|
|
SourceLocation AtLoc,
|
2010-01-17 00:38:58 +08:00
|
|
|
SourceLocation ClassNameLoc,
|
|
|
|
SourceLocation CategoryNameLoc,
|
2011-08-31 03:43:26 +08:00
|
|
|
IdentifierInfo *Id,
|
2012-02-21 04:09:20 +08:00
|
|
|
ObjCInterfaceDecl *IDecl,
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
ObjCTypeParamList *typeParamList,
|
2012-02-21 04:09:20 +08:00
|
|
|
SourceLocation IvarLBraceLoc,
|
|
|
|
SourceLocation IvarRBraceLoc) {
|
2018-04-10 06:14:10 +08:00
|
|
|
auto *CatDecl =
|
2013-11-22 17:01:48 +08:00
|
|
|
new (C, DC) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id,
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
IDecl, typeParamList, IvarLBraceLoc,
|
|
|
|
IvarRBraceLoc);
|
2011-08-31 03:43:26 +08:00
|
|
|
if (IDecl) {
|
|
|
|
// Link this category into its class's category list.
|
2013-01-17 07:00:23 +08:00
|
|
|
CatDecl->NextClassCategory = IDecl->getCategoryListRaw();
|
2011-12-15 13:27:12 +08:00
|
|
|
if (IDecl->hasDefinition()) {
|
2013-01-17 07:00:23 +08:00
|
|
|
IDecl->setCategoryListRaw(CatDecl);
|
2011-12-15 13:27:12 +08:00
|
|
|
if (ASTMutationListener *L = C.getASTMutationListener())
|
|
|
|
L->AddedObjCCategoryToInterface(CatDecl, IDecl);
|
|
|
|
}
|
2011-08-31 03:43:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return CatDecl;
|
|
|
|
}
|
|
|
|
|
2013-11-22 17:01:48 +08:00
|
|
|
ObjCCategoryDecl *ObjCCategoryDecl::CreateDeserialized(ASTContext &C,
|
2012-01-06 05:55:30 +08:00
|
|
|
unsigned ID) {
|
2014-05-12 13:36:57 +08:00
|
|
|
return new (C, ID) ObjCCategoryDecl(nullptr, SourceLocation(),
|
|
|
|
SourceLocation(), SourceLocation(),
|
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters,
and attach lists of type parameters to Objective-C classes,
categories, forward declarations, and extensions as
appropriate. Perform semantic analysis of type bounds for type
parameters, both in isolation and across classes/categories/extensions
to ensure consistency.
Also handle (de-)serialization of Objective-C type parameter lists,
along with sundry other things one must do to add a new declaration to
Clang.
Note that Objective-C type parameters are typedef name declarations,
like typedefs and C++11 type aliases, in support of type erasure.
Part of rdar://problem/6294649.
llvm-svn: 241541
2015-07-07 11:57:15 +08:00
|
|
|
nullptr, nullptr, nullptr);
|
2008-03-17 04:34:23 +08:00
|
|
|
}
|
|
|
|
|
2009-07-21 08:05:53 +08:00
|
|
|
ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const {
|
|
|
|
return getASTContext().getObjCImplementation(
|
|
|
|
const_cast<ObjCCategoryDecl*>(this));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObjCCategoryDecl::setImplementation(ObjCCategoryImplDecl *ImplD) {
|
|
|
|
getASTContext().setObjCImplementation(this, ImplD);
|
|
|
|
}
|
|
|
|
|
2015-07-07 14:20:12 +08:00
|
|
|
void ObjCCategoryDecl::setTypeParamList(ObjCTypeParamList *TPL) {
|
|
|
|
TypeParamList = TPL;
|
|
|
|
if (!TPL)
|
|
|
|
return;
|
|
|
|
// Set the declaration context of each of the type parameters.
|
2018-04-10 06:14:10 +08:00
|
|
|
for (auto *typeParam : *TypeParamList)
|
2015-07-07 14:20:12 +08:00
|
|
|
typeParam->setDeclContext(this);
|
|
|
|
}
|
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ObjCCategoryImplDecl
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-11-23 05:32:07 +08:00
|
|
|
void ObjCCategoryImplDecl::anchor() {}
|
2011-12-20 10:48:34 +08:00
|
|
|
|
2008-03-17 04:53:07 +08:00
|
|
|
ObjCCategoryImplDecl *
|
2009-01-09 08:49:46 +08:00
|
|
|
ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC,
|
2011-10-04 12:48:02 +08:00
|
|
|
IdentifierInfo *Id,
|
|
|
|
ObjCInterfaceDecl *ClassInterface,
|
|
|
|
SourceLocation nameLoc,
|
2011-12-09 08:31:40 +08:00
|
|
|
SourceLocation atStartLoc,
|
|
|
|
SourceLocation CategoryNameLoc) {
|
2011-12-23 08:31:02 +08:00
|
|
|
if (ClassInterface && ClassInterface->hasDefinition())
|
|
|
|
ClassInterface = ClassInterface->getDefinition();
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, DC) ObjCCategoryImplDecl(DC, Id, ClassInterface, nameLoc,
|
|
|
|
atStartLoc, CategoryNameLoc);
|
2008-03-17 04:53:07 +08:00
|
|
|
}
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
ObjCCategoryImplDecl *ObjCCategoryImplDecl::CreateDeserialized(ASTContext &C,
|
2012-01-06 05:55:30 +08:00
|
|
|
unsigned ID) {
|
2014-05-12 13:36:57 +08:00
|
|
|
return new (C, ID) ObjCCategoryImplDecl(nullptr, nullptr, nullptr,
|
|
|
|
SourceLocation(), SourceLocation(),
|
|
|
|
SourceLocation());
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
2009-10-30 05:11:04 +08:00
|
|
|
ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryDecl() const {
|
2010-03-20 04:39:03 +08:00
|
|
|
// The class interface might be NULL if we are working with invalid code.
|
|
|
|
if (const ObjCInterfaceDecl *ID = getClassInterface())
|
|
|
|
return ID->FindCategoryDeclaration(getIdentifier());
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2009-07-28 13:11:05 +08:00
|
|
|
}
|
|
|
|
|
2017-11-23 05:32:07 +08:00
|
|
|
void ObjCImplDecl::anchor() {}
|
2011-12-20 10:48:34 +08:00
|
|
|
|
2009-06-30 10:36:12 +08:00
|
|
|
void ObjCImplDecl::addPropertyImplementation(ObjCPropertyImplDecl *property) {
|
2009-04-23 10:42:49 +08:00
|
|
|
// FIXME: The context should be correct before we get here.
|
2009-04-23 09:02:12 +08:00
|
|
|
property->setLexicalDeclContext(this);
|
2009-06-30 10:36:12 +08:00
|
|
|
addDecl(property);
|
2009-04-23 09:02:12 +08:00
|
|
|
}
|
|
|
|
|
2009-07-21 08:05:53 +08:00
|
|
|
void ObjCImplDecl::setClassInterface(ObjCInterfaceDecl *IFace) {
|
|
|
|
ASTContext &Ctx = getASTContext();
|
|
|
|
|
2018-04-10 06:14:10 +08:00
|
|
|
if (auto *ImplD = dyn_cast_or_null<ObjCImplementationDecl>(this)) {
|
2009-07-21 08:05:53 +08:00
|
|
|
if (IFace)
|
|
|
|
Ctx.setObjCImplementation(IFace, ImplD);
|
|
|
|
|
2018-04-10 06:14:10 +08:00
|
|
|
} else if (auto *ImplD = dyn_cast_or_null<ObjCCategoryImplDecl>(this)) {
|
2009-07-21 08:05:53 +08:00
|
|
|
if (ObjCCategoryDecl *CD = IFace->FindCategoryDeclaration(getIdentifier()))
|
|
|
|
Ctx.setObjCImplementation(CD, ImplD);
|
|
|
|
}
|
|
|
|
|
|
|
|
ClassInterface = IFace;
|
|
|
|
}
|
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
/// FindPropertyImplIvarDecl - This method lookup the ivar in the list of
|
2013-03-13 01:43:00 +08:00
|
|
|
/// properties implemented in this \@implementation block and returns
|
2009-02-21 04:59:54 +08:00
|
|
|
/// the implemented property that uses it.
|
2009-03-01 02:42:10 +08:00
|
|
|
ObjCPropertyImplDecl *ObjCImplDecl::
|
2009-06-30 10:36:12 +08:00
|
|
|
FindPropertyImplIvarDecl(IdentifierInfo *ivarId) const {
|
2014-03-14 23:02:45 +08:00
|
|
|
for (auto *PID : property_impls())
|
2009-02-21 04:59:54 +08:00
|
|
|
if (PID->getPropertyIvarDecl() &&
|
|
|
|
PID->getPropertyIvarDecl()->getIdentifier() == ivarId)
|
|
|
|
return PID;
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2009-01-09 01:28:14 +08:00
|
|
|
}
|
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
/// FindPropertyImplDecl - This method looks up a previous ObjCPropertyImplDecl
|
2012-06-16 06:30:14 +08:00
|
|
|
/// added to the list of those properties \@synthesized/\@dynamic in this
|
|
|
|
/// category \@implementation block.
|
2009-03-01 02:42:10 +08:00
|
|
|
ObjCPropertyImplDecl *ObjCImplDecl::
|
2016-01-29 02:49:28 +08:00
|
|
|
FindPropertyImplDecl(IdentifierInfo *Id,
|
|
|
|
ObjCPropertyQueryKind QueryKind) const {
|
|
|
|
ObjCPropertyImplDecl *ClassPropImpl = nullptr;
|
2014-03-14 23:02:45 +08:00
|
|
|
for (auto *PID : property_impls())
|
2016-01-29 02:49:28 +08:00
|
|
|
// If queryKind is unknown, we return the instance property if one
|
|
|
|
// exists; otherwise we return the class property.
|
|
|
|
if (PID->getPropertyDecl()->getIdentifier() == Id) {
|
|
|
|
if ((QueryKind == ObjCPropertyQueryKind::OBJC_PR_query_unknown &&
|
|
|
|
!PID->getPropertyDecl()->isClassProperty()) ||
|
|
|
|
(QueryKind == ObjCPropertyQueryKind::OBJC_PR_query_class &&
|
|
|
|
PID->getPropertyDecl()->isClassProperty()) ||
|
|
|
|
(QueryKind == ObjCPropertyQueryKind::OBJC_PR_query_instance &&
|
|
|
|
!PID->getPropertyDecl()->isClassProperty()))
|
|
|
|
return PID;
|
|
|
|
|
|
|
|
if (PID->getPropertyDecl()->isClassProperty())
|
|
|
|
ClassPropImpl = PID;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (QueryKind == ObjCPropertyQueryKind::OBJC_PR_query_unknown)
|
|
|
|
// We can't find the instance property, return the class property.
|
|
|
|
return ClassPropImpl;
|
|
|
|
|
2014-05-12 13:36:57 +08:00
|
|
|
return nullptr;
|
2008-04-22 03:04:53 +08:00
|
|
|
}
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
raw_ostream &clang::operator<<(raw_ostream &OS,
|
2012-02-07 19:57:45 +08:00
|
|
|
const ObjCCategoryImplDecl &CID) {
|
|
|
|
OS << CID.getName();
|
2010-04-17 17:33:03 +08:00
|
|
|
return OS;
|
|
|
|
}
|
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ObjCImplementationDecl
|
|
|
|
//===----------------------------------------------------------------------===//
|
2008-03-16 08:19:01 +08:00
|
|
|
|
2017-11-23 05:32:07 +08:00
|
|
|
void ObjCImplementationDecl::anchor() {}
|
2011-12-20 10:48:34 +08:00
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
ObjCImplementationDecl *
|
2009-09-09 23:08:12 +08:00
|
|
|
ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC,
|
2009-02-21 04:59:54 +08:00
|
|
|
ObjCInterfaceDecl *ClassInterface,
|
2011-10-04 12:48:02 +08:00
|
|
|
ObjCInterfaceDecl *SuperDecl,
|
|
|
|
SourceLocation nameLoc,
|
2012-02-21 04:09:20 +08:00
|
|
|
SourceLocation atStartLoc,
|
2013-05-04 02:05:44 +08:00
|
|
|
SourceLocation superLoc,
|
2012-02-21 04:09:20 +08:00
|
|
|
SourceLocation IvarLBraceLoc,
|
|
|
|
SourceLocation IvarRBraceLoc) {
|
2011-12-23 08:31:02 +08:00
|
|
|
if (ClassInterface && ClassInterface->hasDefinition())
|
|
|
|
ClassInterface = ClassInterface->getDefinition();
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, DC) ObjCImplementationDecl(DC, ClassInterface, SuperDecl,
|
|
|
|
nameLoc, atStartLoc, superLoc,
|
|
|
|
IvarLBraceLoc, IvarRBraceLoc);
|
2009-02-21 04:59:54 +08:00
|
|
|
}
|
2008-03-16 08:19:01 +08:00
|
|
|
|
2012-01-06 05:55:30 +08:00
|
|
|
ObjCImplementationDecl *
|
|
|
|
ObjCImplementationDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
2014-05-12 13:36:57 +08:00
|
|
|
return new (C, ID) ObjCImplementationDecl(nullptr, nullptr, nullptr,
|
|
|
|
SourceLocation(), SourceLocation());
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
2011-07-22 12:15:06 +08:00
|
|
|
void ObjCImplementationDecl::setIvarInitializers(ASTContext &C,
|
|
|
|
CXXCtorInitializer ** initializers,
|
|
|
|
unsigned numInitializers) {
|
|
|
|
if (numInitializers > 0) {
|
|
|
|
NumIvarInitializers = numInitializers;
|
2018-04-10 06:14:10 +08:00
|
|
|
auto **ivarInitializers = new (C) CXXCtorInitializer*[NumIvarInitializers];
|
2011-07-22 12:15:06 +08:00
|
|
|
memcpy(ivarInitializers, initializers,
|
|
|
|
numInitializers * sizeof(CXXCtorInitializer*));
|
|
|
|
IvarInitializers = ivarInitializers;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-24 14:36:48 +08:00
|
|
|
ObjCImplementationDecl::init_const_iterator
|
|
|
|
ObjCImplementationDecl::init_begin() const {
|
|
|
|
return IvarInitializers.get(getASTContext().getExternalSource());
|
|
|
|
}
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
raw_ostream &clang::operator<<(raw_ostream &OS,
|
2012-02-07 19:57:45 +08:00
|
|
|
const ObjCImplementationDecl &ID) {
|
|
|
|
OS << ID.getName();
|
2010-04-17 17:33:03 +08:00
|
|
|
return OS;
|
|
|
|
}
|
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ObjCCompatibleAliasDecl
|
|
|
|
//===----------------------------------------------------------------------===//
|
2008-03-16 08:19:01 +08:00
|
|
|
|
2017-11-23 05:32:07 +08:00
|
|
|
void ObjCCompatibleAliasDecl::anchor() {}
|
2011-12-20 10:48:34 +08:00
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
ObjCCompatibleAliasDecl *
|
|
|
|
ObjCCompatibleAliasDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation L,
|
2009-09-09 23:08:12 +08:00
|
|
|
IdentifierInfo *Id,
|
2009-02-21 04:59:54 +08:00
|
|
|
ObjCInterfaceDecl* AliasedClass) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, DC) ObjCCompatibleAliasDecl(DC, L, Id, AliasedClass);
|
2008-03-16 08:19:01 +08:00
|
|
|
}
|
|
|
|
|
2012-01-06 05:55:30 +08:00
|
|
|
ObjCCompatibleAliasDecl *
|
|
|
|
ObjCCompatibleAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
2014-05-12 13:36:57 +08:00
|
|
|
return new (C, ID) ObjCCompatibleAliasDecl(nullptr, SourceLocation(),
|
|
|
|
nullptr, nullptr);
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ObjCPropertyDecl
|
|
|
|
//===----------------------------------------------------------------------===//
|
2008-03-16 08:19:01 +08:00
|
|
|
|
2017-11-23 05:32:07 +08:00
|
|
|
void ObjCPropertyDecl::anchor() {}
|
2011-12-20 10:48:34 +08:00
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
ObjCPropertyDecl *ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation L,
|
|
|
|
IdentifierInfo *Id,
|
2010-01-22 01:36:00 +08:00
|
|
|
SourceLocation AtLoc,
|
2012-03-01 06:18:55 +08:00
|
|
|
SourceLocation LParenLoc,
|
2015-06-20 02:14:38 +08:00
|
|
|
QualType T,
|
|
|
|
TypeSourceInfo *TSI,
|
2009-02-21 04:59:54 +08:00
|
|
|
PropertyControl propControl) {
|
2015-06-20 02:14:38 +08:00
|
|
|
return new (C, DC) ObjCPropertyDecl(DC, L, Id, AtLoc, LParenLoc, T, TSI,
|
|
|
|
propControl);
|
2008-03-16 08:19:01 +08:00
|
|
|
}
|
|
|
|
|
2013-11-22 17:01:48 +08:00
|
|
|
ObjCPropertyDecl *ObjCPropertyDecl::CreateDeserialized(ASTContext &C,
|
2012-01-06 05:55:30 +08:00
|
|
|
unsigned ID) {
|
2014-05-12 13:36:57 +08:00
|
|
|
return new (C, ID) ObjCPropertyDecl(nullptr, SourceLocation(), nullptr,
|
|
|
|
SourceLocation(), SourceLocation(),
|
2015-06-20 02:14:38 +08:00
|
|
|
QualType(), nullptr, None);
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
llvm-svn: 241543
2015-07-07 11:57:53 +08:00
|
|
|
QualType ObjCPropertyDecl::getUsageType(QualType objectType) const {
|
|
|
|
return DeclType.substObjCMemberType(objectType, getDeclContext(),
|
|
|
|
ObjCSubstitutionContext::Property);
|
|
|
|
}
|
|
|
|
|
2021-04-06 07:23:27 +08:00
|
|
|
bool ObjCPropertyDecl::isDirectProperty() const {
|
|
|
|
return (PropertyAttributes & ObjCPropertyAttribute::kind_direct) &&
|
|
|
|
!getASTContext().getLangOpts().ObjCDisableDirectMethodsForTesting;
|
|
|
|
}
|
|
|
|
|
2009-02-21 04:59:54 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ObjCPropertyImplDecl
|
|
|
|
//===----------------------------------------------------------------------===//
|
2008-03-17 09:19:02 +08:00
|
|
|
|
2008-04-23 08:06:01 +08:00
|
|
|
ObjCPropertyImplDecl *ObjCPropertyImplDecl::Create(ASTContext &C,
|
2009-01-09 08:49:46 +08:00
|
|
|
DeclContext *DC,
|
2008-04-23 08:06:01 +08:00
|
|
|
SourceLocation atLoc,
|
|
|
|
SourceLocation L,
|
|
|
|
ObjCPropertyDecl *property,
|
2008-08-26 12:47:31 +08:00
|
|
|
Kind PK,
|
2010-11-17 09:03:52 +08:00
|
|
|
ObjCIvarDecl *ivar,
|
|
|
|
SourceLocation ivarLoc) {
|
2013-11-22 17:01:48 +08:00
|
|
|
return new (C, DC) ObjCPropertyImplDecl(DC, atLoc, L, property, PK, ivar,
|
|
|
|
ivarLoc);
|
2008-04-23 08:06:01 +08:00
|
|
|
}
|
2008-03-17 09:19:02 +08:00
|
|
|
|
2013-11-22 17:01:48 +08:00
|
|
|
ObjCPropertyImplDecl *ObjCPropertyImplDecl::CreateDeserialized(ASTContext &C,
|
2012-01-06 05:55:30 +08:00
|
|
|
unsigned ID) {
|
2014-05-12 13:36:57 +08:00
|
|
|
return new (C, ID) ObjCPropertyImplDecl(nullptr, SourceLocation(),
|
|
|
|
SourceLocation(), nullptr, Dynamic,
|
|
|
|
nullptr, SourceLocation());
|
2012-01-06 05:55:30 +08:00
|
|
|
}
|
|
|
|
|
2010-11-17 09:03:52 +08:00
|
|
|
SourceRange ObjCPropertyImplDecl::getSourceRange() const {
|
|
|
|
SourceLocation EndLoc = getLocation();
|
|
|
|
if (IvarLoc.isValid())
|
|
|
|
EndLoc = IvarLoc;
|
2008-04-04 14:12:32 +08:00
|
|
|
|
2010-11-17 09:03:52 +08:00
|
|
|
return SourceRange(AtLoc, EndLoc);
|
|
|
|
}
|