diff options
Diffstat (limited to 'clang/lib/AST/NSAPI.cpp')
| -rw-r--r-- | clang/lib/AST/NSAPI.cpp | 611 | 
1 files changed, 611 insertions, 0 deletions
| diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp new file mode 100644 index 000000000000..ae6ff04f5126 --- /dev/null +++ b/clang/lib/AST/NSAPI.cpp @@ -0,0 +1,611 @@ +//===--- NSAPI.cpp - NSFoundation APIs ------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/NSAPI.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; + +NSAPI::NSAPI(ASTContext &ctx) +  : Ctx(ctx), ClassIds(), BOOLId(nullptr), NSIntegerId(nullptr), +    NSUIntegerId(nullptr), NSASCIIStringEncodingId(nullptr), +    NSUTF8StringEncodingId(nullptr) {} + +IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const { +  static const char *ClassName[NumClassIds] = { +    "NSObject", +    "NSString", +    "NSArray", +    "NSMutableArray", +    "NSDictionary", +    "NSMutableDictionary", +    "NSNumber", +    "NSMutableSet", +    "NSMutableOrderedSet", +    "NSValue" +  }; + +  if (!ClassIds[K]) +    return (ClassIds[K] = &Ctx.Idents.get(ClassName[K])); + +  return ClassIds[K]; +} + +Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const { +  if (NSStringSelectors[MK].isNull()) { +    Selector Sel; +    switch (MK) { +    case NSStr_stringWithString: +      Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithString")); +      break; +    case NSStr_stringWithUTF8String: +      Sel = Ctx.Selectors.getUnarySelector( +                                       &Ctx.Idents.get("stringWithUTF8String")); +      break; +    case NSStr_initWithUTF8String: +      Sel = Ctx.Selectors.getUnarySelector( +                                       &Ctx.Idents.get("initWithUTF8String")); +      break; +    case NSStr_stringWithCStringEncoding: { +      IdentifierInfo *KeyIdents[] = { +        &Ctx.Idents.get("stringWithCString"), +        &Ctx.Idents.get("encoding") +      }; +      Sel = Ctx.Selectors.getSelector(2, KeyIdents); +      break; +    } +    case NSStr_stringWithCString: +      Sel= Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithCString")); +      break; +    case NSStr_initWithString: +      Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithString")); +      break; +    } +    return (NSStringSelectors[MK] = Sel); +  } + +  return NSStringSelectors[MK]; +} + +Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const { +  if (NSArraySelectors[MK].isNull()) { +    Selector Sel; +    switch (MK) { +    case NSArr_array: +      Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("array")); +      break; +    case NSArr_arrayWithArray: +      Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithArray")); +      break; +    case NSArr_arrayWithObject: +      Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObject")); +      break; +    case NSArr_arrayWithObjects: +      Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObjects")); +      break; +    case NSArr_arrayWithObjectsCount: { +      IdentifierInfo *KeyIdents[] = { +        &Ctx.Idents.get("arrayWithObjects"), +        &Ctx.Idents.get("count") +      }; +      Sel = Ctx.Selectors.getSelector(2, KeyIdents); +      break; +    } +    case NSArr_initWithArray: +      Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithArray")); +      break; +    case NSArr_initWithObjects: +      Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithObjects")); +      break; +    case NSArr_objectAtIndex: +      Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectAtIndex")); +      break; +    case NSMutableArr_replaceObjectAtIndex: { +      IdentifierInfo *KeyIdents[] = { +        &Ctx.Idents.get("replaceObjectAtIndex"), +        &Ctx.Idents.get("withObject") +      }; +      Sel = Ctx.Selectors.getSelector(2, KeyIdents); +      break; +    } +    case NSMutableArr_addObject: +      Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject")); +      break; +    case NSMutableArr_insertObjectAtIndex: { +      IdentifierInfo *KeyIdents[] = { +        &Ctx.Idents.get("insertObject"), +        &Ctx.Idents.get("atIndex") +      }; +      Sel = Ctx.Selectors.getSelector(2, KeyIdents); +      break; +    } +    case NSMutableArr_setObjectAtIndexedSubscript: { +      IdentifierInfo *KeyIdents[] = { +        &Ctx.Idents.get("setObject"), +        &Ctx.Idents.get("atIndexedSubscript") +      }; +      Sel = Ctx.Selectors.getSelector(2, KeyIdents); +      break; +    } +    } +    return (NSArraySelectors[MK] = Sel); +  } + +  return NSArraySelectors[MK]; +} + +Optional<NSAPI::NSArrayMethodKind> NSAPI::getNSArrayMethodKind(Selector Sel) { +  for (unsigned i = 0; i != NumNSArrayMethods; ++i) { +    NSArrayMethodKind MK = NSArrayMethodKind(i); +    if (Sel == getNSArraySelector(MK)) +      return MK; +  } + +  return None; +} + +Selector NSAPI::getNSDictionarySelector( +                                       NSDictionaryMethodKind MK) const { +  if (NSDictionarySelectors[MK].isNull()) { +    Selector Sel; +    switch (MK) { +    case NSDict_dictionary: +      Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("dictionary")); +      break; +    case NSDict_dictionaryWithDictionary: +      Sel = Ctx.Selectors.getUnarySelector( +                                   &Ctx.Idents.get("dictionaryWithDictionary")); +      break; +    case NSDict_dictionaryWithObjectForKey: { +      IdentifierInfo *KeyIdents[] = { +        &Ctx.Idents.get("dictionaryWithObject"), +        &Ctx.Idents.get("forKey") +      }; +      Sel = Ctx.Selectors.getSelector(2, KeyIdents); +      break; +    } +    case NSDict_dictionaryWithObjectsForKeys: { +      IdentifierInfo *KeyIdents[] = { +        &Ctx.Idents.get("dictionaryWithObjects"), +        &Ctx.Idents.get("forKeys") +      }; +      Sel = Ctx.Selectors.getSelector(2, KeyIdents); +      break; +    } +    case NSDict_dictionaryWithObjectsForKeysCount: { +      IdentifierInfo *KeyIdents[] = { +        &Ctx.Idents.get("dictionaryWithObjects"), +        &Ctx.Idents.get("forKeys"), +        &Ctx.Idents.get("count") +      }; +      Sel = Ctx.Selectors.getSelector(3, KeyIdents); +      break; +    } +    case NSDict_dictionaryWithObjectsAndKeys: +      Sel = Ctx.Selectors.getUnarySelector( +                               &Ctx.Idents.get("dictionaryWithObjectsAndKeys")); +      break; +    case NSDict_initWithDictionary: +      Sel = Ctx.Selectors.getUnarySelector( +                                         &Ctx.Idents.get("initWithDictionary")); +      break; +    case NSDict_initWithObjectsAndKeys: +      Sel = Ctx.Selectors.getUnarySelector( +                                     &Ctx.Idents.get("initWithObjectsAndKeys")); +      break; +    case NSDict_initWithObjectsForKeys: { +      IdentifierInfo *KeyIdents[] = { +        &Ctx.Idents.get("initWithObjects"), +        &Ctx.Idents.get("forKeys") +      }; +      Sel = Ctx.Selectors.getSelector(2, KeyIdents); +      break; +    } +    case NSDict_objectForKey: +      Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey")); +      break; +    case NSMutableDict_setObjectForKey: { +      IdentifierInfo *KeyIdents[] = { +        &Ctx.Idents.get("setObject"), +        &Ctx.Idents.get("forKey") +      }; +      Sel = Ctx.Selectors.getSelector(2, KeyIdents); +      break; +    } +    case NSMutableDict_setObjectForKeyedSubscript: { +      IdentifierInfo *KeyIdents[] = { +        &Ctx.Idents.get("setObject"), +        &Ctx.Idents.get("forKeyedSubscript") +      }; +      Sel = Ctx.Selectors.getSelector(2, KeyIdents); +      break; +    } +    case NSMutableDict_setValueForKey: { +      IdentifierInfo *KeyIdents[] = { +        &Ctx.Idents.get("setValue"), +        &Ctx.Idents.get("forKey") +      }; +      Sel = Ctx.Selectors.getSelector(2, KeyIdents); +      break; +    } +    } +    return (NSDictionarySelectors[MK] = Sel); +  } + +  return NSDictionarySelectors[MK]; +} + +Optional<NSAPI::NSDictionaryMethodKind> +NSAPI::getNSDictionaryMethodKind(Selector Sel) { +  for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) { +    NSDictionaryMethodKind MK = NSDictionaryMethodKind(i); +    if (Sel == getNSDictionarySelector(MK)) +      return MK; +  } + +  return None; +} + +Selector NSAPI::getNSSetSelector(NSSetMethodKind MK) const { +  if (NSSetSelectors[MK].isNull()) { +    Selector Sel; +    switch (MK) { +    case NSMutableSet_addObject: +      Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject")); +      break; +    case NSOrderedSet_insertObjectAtIndex: { +      IdentifierInfo *KeyIdents[] = { +        &Ctx.Idents.get("insertObject"), +        &Ctx.Idents.get("atIndex") +      }; +      Sel = Ctx.Selectors.getSelector(2, KeyIdents); +      break; +    } +    case NSOrderedSet_setObjectAtIndex: { +      IdentifierInfo *KeyIdents[] = { +        &Ctx.Idents.get("setObject"), +        &Ctx.Idents.get("atIndex") +      }; +      Sel = Ctx.Selectors.getSelector(2, KeyIdents); +      break; +    } +    case NSOrderedSet_setObjectAtIndexedSubscript: { +      IdentifierInfo *KeyIdents[] = { +        &Ctx.Idents.get("setObject"), +        &Ctx.Idents.get("atIndexedSubscript") +      }; +      Sel = Ctx.Selectors.getSelector(2, KeyIdents); +      break; +    } +    case NSOrderedSet_replaceObjectAtIndexWithObject: { +      IdentifierInfo *KeyIdents[] = { +        &Ctx.Idents.get("replaceObjectAtIndex"), +        &Ctx.Idents.get("withObject") +      }; +      Sel = Ctx.Selectors.getSelector(2, KeyIdents); +      break; +    } +    } +    return (NSSetSelectors[MK] = Sel); +  } + +  return NSSetSelectors[MK]; +} + +Optional<NSAPI::NSSetMethodKind> +NSAPI::getNSSetMethodKind(Selector Sel) { +  for (unsigned i = 0; i != NumNSSetMethods; ++i) { +    NSSetMethodKind MK = NSSetMethodKind(i); +    if (Sel == getNSSetSelector(MK)) +      return MK; +  } + +  return None; +} + +Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK, +                                           bool Instance) const { +  static const char *ClassSelectorName[NumNSNumberLiteralMethods] = { +    "numberWithChar", +    "numberWithUnsignedChar", +    "numberWithShort", +    "numberWithUnsignedShort", +    "numberWithInt", +    "numberWithUnsignedInt", +    "numberWithLong", +    "numberWithUnsignedLong", +    "numberWithLongLong", +    "numberWithUnsignedLongLong", +    "numberWithFloat", +    "numberWithDouble", +    "numberWithBool", +    "numberWithInteger", +    "numberWithUnsignedInteger" +  }; +  static const char *InstanceSelectorName[NumNSNumberLiteralMethods] = { +    "initWithChar", +    "initWithUnsignedChar", +    "initWithShort", +    "initWithUnsignedShort", +    "initWithInt", +    "initWithUnsignedInt", +    "initWithLong", +    "initWithUnsignedLong", +    "initWithLongLong", +    "initWithUnsignedLongLong", +    "initWithFloat", +    "initWithDouble", +    "initWithBool", +    "initWithInteger", +    "initWithUnsignedInteger" +  }; + +  Selector *Sels; +  const char **Names; +  if (Instance) { +    Sels = NSNumberInstanceSelectors; +    Names = InstanceSelectorName; +  } else { +    Sels = NSNumberClassSelectors; +    Names = ClassSelectorName; +  } + +  if (Sels[MK].isNull()) +    Sels[MK] = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(Names[MK])); +  return Sels[MK]; +} + +Optional<NSAPI::NSNumberLiteralMethodKind> +NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const { +  for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) { +    NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i); +    if (isNSNumberLiteralSelector(MK, Sel)) +      return MK; +  } + +  return None; +} + +Optional<NSAPI::NSNumberLiteralMethodKind> +NSAPI::getNSNumberFactoryMethodKind(QualType T) const { +  const BuiltinType *BT = T->getAs<BuiltinType>(); +  if (!BT) +    return None; + +  const TypedefType *TDT = T->getAs<TypedefType>(); +  if (TDT) { +    QualType TDTTy = QualType(TDT, 0); +    if (isObjCBOOLType(TDTTy)) +      return NSAPI::NSNumberWithBool; +    if (isObjCNSIntegerType(TDTTy)) +      return NSAPI::NSNumberWithInteger; +    if (isObjCNSUIntegerType(TDTTy)) +      return NSAPI::NSNumberWithUnsignedInteger; +  } + +  switch (BT->getKind()) { +  case BuiltinType::Char_S: +  case BuiltinType::SChar: +    return NSAPI::NSNumberWithChar; +  case BuiltinType::Char_U: +  case BuiltinType::UChar: +    return NSAPI::NSNumberWithUnsignedChar; +  case BuiltinType::Short: +    return NSAPI::NSNumberWithShort; +  case BuiltinType::UShort: +    return NSAPI::NSNumberWithUnsignedShort; +  case BuiltinType::Int: +    return NSAPI::NSNumberWithInt; +  case BuiltinType::UInt: +    return NSAPI::NSNumberWithUnsignedInt; +  case BuiltinType::Long: +    return NSAPI::NSNumberWithLong; +  case BuiltinType::ULong: +    return NSAPI::NSNumberWithUnsignedLong; +  case BuiltinType::LongLong: +    return NSAPI::NSNumberWithLongLong; +  case BuiltinType::ULongLong: +    return NSAPI::NSNumberWithUnsignedLongLong; +  case BuiltinType::Float: +    return NSAPI::NSNumberWithFloat; +  case BuiltinType::Double: +    return NSAPI::NSNumberWithDouble; +  case BuiltinType::Bool: +    return NSAPI::NSNumberWithBool; + +  case BuiltinType::Void: +  case BuiltinType::WChar_U: +  case BuiltinType::WChar_S: +  case BuiltinType::Char8: +  case BuiltinType::Char16: +  case BuiltinType::Char32: +  case BuiltinType::Int128: +  case BuiltinType::LongDouble: +  case BuiltinType::ShortAccum: +  case BuiltinType::Accum: +  case BuiltinType::LongAccum: +  case BuiltinType::UShortAccum: +  case BuiltinType::UAccum: +  case BuiltinType::ULongAccum: +  case BuiltinType::ShortFract: +  case BuiltinType::Fract: +  case BuiltinType::LongFract: +  case BuiltinType::UShortFract: +  case BuiltinType::UFract: +  case BuiltinType::ULongFract: +  case BuiltinType::SatShortAccum: +  case BuiltinType::SatAccum: +  case BuiltinType::SatLongAccum: +  case BuiltinType::SatUShortAccum: +  case BuiltinType::SatUAccum: +  case BuiltinType::SatULongAccum: +  case BuiltinType::SatShortFract: +  case BuiltinType::SatFract: +  case BuiltinType::SatLongFract: +  case BuiltinType::SatUShortFract: +  case BuiltinType::SatUFract: +  case BuiltinType::SatULongFract: +  case BuiltinType::UInt128: +  case BuiltinType::Float16: +  case BuiltinType::Float128: +  case BuiltinType::NullPtr: +  case BuiltinType::ObjCClass: +  case BuiltinType::ObjCId: +  case BuiltinType::ObjCSel: +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ +  case BuiltinType::Id: +#include "clang/Basic/OpenCLImageTypes.def" +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ +  case BuiltinType::Id: +#include "clang/Basic/OpenCLExtensionTypes.def" +  case BuiltinType::OCLSampler: +  case BuiltinType::OCLEvent: +  case BuiltinType::OCLClkEvent: +  case BuiltinType::OCLQueue: +  case BuiltinType::OCLReserveID: +#define SVE_TYPE(Name, Id, SingletonId) \ +  case BuiltinType::Id: +#include "clang/Basic/AArch64SVEACLETypes.def" +  case BuiltinType::BoundMember: +  case BuiltinType::Dependent: +  case BuiltinType::Overload: +  case BuiltinType::UnknownAny: +  case BuiltinType::ARCUnbridgedCast: +  case BuiltinType::Half: +  case BuiltinType::PseudoObject: +  case BuiltinType::BuiltinFn: +  case BuiltinType::OMPArraySection: +    break; +  } + +  return None; +} + +/// Returns true if \param T is a typedef of "BOOL" in objective-c. +bool NSAPI::isObjCBOOLType(QualType T) const { +  return isObjCTypedef(T, "BOOL", BOOLId); +} +/// Returns true if \param T is a typedef of "NSInteger" in objective-c. +bool NSAPI::isObjCNSIntegerType(QualType T) const { +  return isObjCTypedef(T, "NSInteger", NSIntegerId); +} +/// Returns true if \param T is a typedef of "NSUInteger" in objective-c. +bool NSAPI::isObjCNSUIntegerType(QualType T) const { +  return isObjCTypedef(T, "NSUInteger", NSUIntegerId); +} + +StringRef NSAPI::GetNSIntegralKind(QualType T) const { +  if (!Ctx.getLangOpts().ObjC || T.isNull()) +    return StringRef(); + +  while (const TypedefType *TDT = T->getAs<TypedefType>()) { +    StringRef NSIntegralResust = +      llvm::StringSwitch<StringRef>( +        TDT->getDecl()->getDeclName().getAsIdentifierInfo()->getName()) +    .Case("int8_t", "int8_t") +    .Case("int16_t", "int16_t") +    .Case("int32_t", "int32_t") +    .Case("NSInteger", "NSInteger") +    .Case("int64_t", "int64_t") +    .Case("uint8_t", "uint8_t") +    .Case("uint16_t", "uint16_t") +    .Case("uint32_t", "uint32_t") +    .Case("NSUInteger", "NSUInteger") +    .Case("uint64_t", "uint64_t") +    .Default(StringRef()); +    if (!NSIntegralResust.empty()) +      return NSIntegralResust; +    T = TDT->desugar(); +  } +  return StringRef(); +} + +bool NSAPI::isMacroDefined(StringRef Id) const { +  // FIXME: Check whether the relevant module macros are visible. +  return Ctx.Idents.get(Id).hasMacroDefinition(); +} + +bool NSAPI::isSubclassOfNSClass(ObjCInterfaceDecl *InterfaceDecl, +                                NSClassIdKindKind NSClassKind) const { +  if (!InterfaceDecl) { +    return false; +  } + +  IdentifierInfo *NSClassID = getNSClassId(NSClassKind); + +  bool IsSubclass = false; +  do { +    IsSubclass = NSClassID == InterfaceDecl->getIdentifier(); + +    if (IsSubclass) { +      break; +    } +  } while ((InterfaceDecl = InterfaceDecl->getSuperClass())); + +  return IsSubclass; +} + +bool NSAPI::isObjCTypedef(QualType T, +                          StringRef name, IdentifierInfo *&II) const { +  if (!Ctx.getLangOpts().ObjC) +    return false; +  if (T.isNull()) +    return false; + +  if (!II) +    II = &Ctx.Idents.get(name); + +  while (const TypedefType *TDT = T->getAs<TypedefType>()) { +    if (TDT->getDecl()->getDeclName().getAsIdentifierInfo() == II) +      return true; +    T = TDT->desugar(); +  } + +  return false; +} + +bool NSAPI::isObjCEnumerator(const Expr *E, +                             StringRef name, IdentifierInfo *&II) const { +  if (!Ctx.getLangOpts().ObjC) +    return false; +  if (!E) +    return false; + +  if (!II) +    II = &Ctx.Idents.get(name); + +  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) +    if (const EnumConstantDecl * +          EnumD = dyn_cast_or_null<EnumConstantDecl>(DRE->getDecl())) +      return EnumD->getIdentifier() == II; + +  return false; +} + +Selector NSAPI::getOrInitSelector(ArrayRef<StringRef> Ids, +                                  Selector &Sel) const { +  if (Sel.isNull()) { +    SmallVector<IdentifierInfo *, 4> Idents; +    for (ArrayRef<StringRef>::const_iterator +           I = Ids.begin(), E = Ids.end(); I != E; ++I) +      Idents.push_back(&Ctx.Idents.get(*I)); +    Sel = Ctx.Selectors.getSelector(Idents.size(), Idents.data()); +  } +  return Sel; +} + +Selector NSAPI::getOrInitNullarySelector(StringRef Id, Selector &Sel) const { +  if (Sel.isNull()) { +    IdentifierInfo *Ident = &Ctx.Idents.get(Id); +    Sel = Ctx.Selectors.getSelector(0, &Ident); +  } +  return Sel; +} | 
