void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
                                        CheckerContext &C) const {
  const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
  if (!ID)
    return;
  
  if (findKnownClass(ID) == FC_NSString) {
    Selector S = msg.getSelector();
    
    if (S.isUnarySelector())
      return;
    
    // FIXME: This is going to be really slow doing these checks with
    //  lexical comparisons.
    
    std::string NameStr = S.getAsString();
    StringRef Name(NameStr);
    assert(!Name.empty());
    
    // FIXME: Checking for initWithFormat: will not work in most cases
    //  yet because [NSString alloc] returns id, not NSString*.  We will
    //  need support for tracking expected-type information in the analyzer
    //  to find these errors.
    if (Name == "caseInsensitiveCompare:" ||
        Name == "compare:" ||
        Name == "compare:options:" ||
        Name == "compare:options:range:" ||
        Name == "compare:options:range:locale:" ||
        Name == "componentsSeparatedByCharactersInSet:" ||
        Name == "initWithFormat:") {
      if (isNil(msg.getArgSVal(0)))
        WarnNilArg(C, msg, 0);
    }
  }
}
bool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N,
                                              const ObjCMessageExpr* ME) {

  Selector S = ME->getSelector();

  if (S.isUnarySelector())
    return false;

  // FIXME: This is going to be really slow doing these checks with
  //  lexical comparisons.

  std::string NameStr = S.getAsString();
  llvm::StringRef Name(NameStr);
  assert(!Name.empty());

  // FIXME: Checking for initWithFormat: will not work in most cases
  //  yet because [NSString alloc] returns id, not NSString*.  We will
  //  need support for tracking expected-type information in the analyzer
  //  to find these errors.
  if (Name == "caseInsensitiveCompare:" ||
      Name == "compare:" ||
      Name == "compare:options:" ||
      Name == "compare:options:range:" ||
      Name == "compare:options:range:locale:" ||
      Name == "componentsSeparatedByCharactersInSet:" ||
      Name == "initWithFormat:")
    return CheckNilArg(N, 0);

  return false;
}
Ejemplo n.º 3
0
void ODRHash::AddDeclarationName(DeclarationName Name) {
  // Index all DeclarationName and use index numbers to refer to them.
  auto Result = DeclNameMap.insert(std::make_pair(Name, DeclNameMap.size()));
  ID.AddInteger(Result.first->second);
  if (!Result.second) {
    // If found in map, the the DeclarationName has previously been processed.
    return;
  }

  // First time processing each DeclarationName, also process its details.
  AddBoolean(Name.isEmpty());
  if (Name.isEmpty())
    return;

  auto Kind = Name.getNameKind();
  ID.AddInteger(Kind);
  switch (Kind) {
  case DeclarationName::Identifier:
    AddIdentifierInfo(Name.getAsIdentifierInfo());
    break;
  case DeclarationName::ObjCZeroArgSelector:
  case DeclarationName::ObjCOneArgSelector:
  case DeclarationName::ObjCMultiArgSelector: {
    Selector S = Name.getObjCSelector();
    AddBoolean(S.isNull());
    AddBoolean(S.isKeywordSelector());
    AddBoolean(S.isUnarySelector());
    unsigned NumArgs = S.getNumArgs();
    for (unsigned i = 0; i < NumArgs; ++i) {
      AddIdentifierInfo(S.getIdentifierInfoForSlot(i));
    }
    break;
  }
  case DeclarationName::CXXConstructorName:
  case DeclarationName::CXXDestructorName:
    AddQualType(Name.getCXXNameType());
    break;
  case DeclarationName::CXXOperatorName:
    ID.AddInteger(Name.getCXXOverloadedOperator());
    break;
  case DeclarationName::CXXLiteralOperatorName:
    AddIdentifierInfo(Name.getCXXLiteralIdentifier());
    break;
  case DeclarationName::CXXConversionFunctionName:
    AddQualType(Name.getCXXNameType());
    break;
  case DeclarationName::CXXUsingDirective:
    break;
  case DeclarationName::CXXDeductionGuideName: {
    auto *Template = Name.getCXXDeductionGuideTemplate();
    AddBoolean(Template);
    if (Template) {
      AddDecl(Template);
    }
  }
  }
}
bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
                                              CheckerContext &C) const {
  Selector S = M.getSelector();
  // Initialize the identifiers on first use.
  if (!CountSelectorII)
    CountSelectorII = &C.getASTContext().Idents.get("count");

  // If the method returns collection count, record the value.
  return S.isUnarySelector() &&
         (S.getIdentifierInfoForSlot(0) == CountSelectorII);
}
Ejemplo n.º 5
0
void ODRHash::AddDeclarationName(DeclarationName Name) {
  AddBoolean(Name.isEmpty());
  if (Name.isEmpty())
    return;

  auto Kind = Name.getNameKind();
  ID.AddInteger(Kind);
  switch (Kind) {
  case DeclarationName::Identifier:
    AddIdentifierInfo(Name.getAsIdentifierInfo());
    break;
  case DeclarationName::ObjCZeroArgSelector:
  case DeclarationName::ObjCOneArgSelector:
  case DeclarationName::ObjCMultiArgSelector: {
    Selector S = Name.getObjCSelector();
    AddBoolean(S.isNull());
    AddBoolean(S.isKeywordSelector());
    AddBoolean(S.isUnarySelector());
    unsigned NumArgs = S.getNumArgs();
    for (unsigned i = 0; i < NumArgs; ++i) {
      AddIdentifierInfo(S.getIdentifierInfoForSlot(i));
    }
    break;
  }
  case DeclarationName::CXXConstructorName:
  case DeclarationName::CXXDestructorName:
    AddQualType(Name.getCXXNameType());
    break;
  case DeclarationName::CXXOperatorName:
    ID.AddInteger(Name.getCXXOverloadedOperator());
    break;
  case DeclarationName::CXXLiteralOperatorName:
    AddIdentifierInfo(Name.getCXXLiteralIdentifier());
    break;
  case DeclarationName::CXXConversionFunctionName:
    AddQualType(Name.getCXXNameType());
    break;
  case DeclarationName::CXXUsingDirective:
    break;
  case DeclarationName::CXXDeductionGuideName: {
    auto *Template = Name.getCXXDeductionGuideTemplate();
    AddBoolean(Template);
    if (Template) {
      AddDecl(Template);
    }
  }
  }
}
Ejemplo n.º 6
0
ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
  IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
  if (!first) return OMF_None;

  StringRef name = first->getName();
  if (sel.isUnarySelector()) {
    if (name == "autorelease") return OMF_autorelease;
    if (name == "dealloc") return OMF_dealloc;
    if (name == "finalize") return OMF_finalize;
    if (name == "release") return OMF_release;
    if (name == "retain") return OMF_retain;
    if (name == "retainCount") return OMF_retainCount;
    if (name == "self") return OMF_self;
    if (name == "initialize") return OMF_initialize;
  }

  if (name == "performSelector" || name == "performSelectorInBackground" ||
      name == "performSelectorOnMainThread")
    return OMF_performSelector;

  // The other method families may begin with a prefix of underscores.
  while (!name.empty() && name.front() == '_')
    name = name.substr(1);

  if (name.empty()) return OMF_None;
  switch (name.front()) {
  case 'a':
    if (startsWithWord(name, "alloc")) return OMF_alloc;
    break;
  case 'c':
    if (startsWithWord(name, "copy")) return OMF_copy;
    break;
  case 'i':
    if (startsWithWord(name, "init")) return OMF_init;
    break;
  case 'm':
    if (startsWithWord(name, "mutableCopy")) return OMF_mutableCopy;
    break;
  case 'n':
    if (startsWithWord(name, "new")) return OMF_new;
    break;
  default:
    break;
  }

  return OMF_None;
}
Ejemplo n.º 7
0
/// \brief Get the ASTContext-specific selector.
Selector GlobalSelector::getSelector(ASTContext &AST) const {
  if (isInvalid())
    return Selector();

  Selector GlobSel = Selector(reinterpret_cast<uintptr_t>(Val));

  llvm::SmallVector<IdentifierInfo *, 8> Ids;
  for (unsigned i = 0, e = GlobSel.isUnarySelector() ? 1 : GlobSel.getNumArgs();
         i != e; ++i) {
    IdentifierInfo *GlobII = GlobSel.getIdentifierInfoForSlot(i);
    IdentifierInfo *II = &AST.Idents.get(GlobII->getName(),
                                       GlobII->getName() + GlobII->getLength());
    Ids.push_back(II);
  }

  return AST.Selectors.getSelector(GlobSel.getNumArgs(), Ids.data());
}
Ejemplo n.º 8
0
/// \brief Get a GlobalSelector for the ASTContext-specific selector.
GlobalSelector GlobalSelector::get(Selector Sel, Program &Prog) {
  if (Sel.isNull())
    return GlobalSelector();

  ProgramImpl &ProgImpl = *static_cast<ProgramImpl*>(Prog.Impl);

  llvm::SmallVector<IdentifierInfo *, 8> Ids;
  for (unsigned i = 0, e = Sel.isUnarySelector() ? 1 : Sel.getNumArgs();
         i != e; ++i) {
    IdentifierInfo *II = Sel.getIdentifierInfoForSlot(i);
    IdentifierInfo *GlobII = &ProgImpl.getIdents().get(II->getName(),
                                               II->getName() + II->getLength());
    Ids.push_back(GlobII);
  }

  Selector GlobSel = ProgImpl.getSelectors().getSelector(Sel.getNumArgs(),
                                                         Ids.data());
  return GlobalSelector(GlobSel.getAsOpaquePtr());
}
Ejemplo n.º 9
0
void NilArgChecker::preVisitObjCMessage(CheckerContext &C,
                                        ObjCMessage msg)
{
  const ObjCInterfaceType *ReceiverType = GetReceiverType(msg);
  if (!ReceiverType)
    return;
  
  if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
    Selector S = msg.getSelector();
    
    if (S.isUnarySelector())
      return;
    
    // FIXME: This is going to be really slow doing these checks with
    //  lexical comparisons.
    
    std::string NameStr = S.getAsString();
    llvm::StringRef Name(NameStr);
    assert(!Name.empty());
    
    // FIXME: Checking for initWithFormat: will not work in most cases
    //  yet because [NSString alloc] returns id, not NSString*.  We will
    //  need support for tracking expected-type information in the analyzer
    //  to find these errors.
    if (Name == "caseInsensitiveCompare:" ||
        Name == "compare:" ||
        Name == "compare:options:" ||
        Name == "compare:options:range:" ||
        Name == "compare:options:range:locale:" ||
        Name == "componentsSeparatedByCharactersInSet:" ||
        Name == "initWithFormat:") {
      if (isNil(msg.getArgSVal(0, C.getState())))
        WarnNilArg(C, msg, 0);
    }
  }
}
void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
                                        CheckerContext &C) const {
  const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
  if (!ID)
    return;

  FoundationClass Class = findKnownClass(ID);

  static const unsigned InvalidArgIndex = UINT_MAX;
  unsigned Arg = InvalidArgIndex;
  bool CanBeSubscript = false;

  if (Class == FC_NSString) {
    Selector S = msg.getSelector();

    if (S.isUnarySelector())
      return;

    if (StringSelectors.empty()) {
      ASTContext &Ctx = C.getASTContext();
      Selector Sels[] = {
        getKeywordSelector(Ctx, "caseInsensitiveCompare", nullptr),
        getKeywordSelector(Ctx, "compare", nullptr),
        getKeywordSelector(Ctx, "compare", "options", nullptr),
        getKeywordSelector(Ctx, "compare", "options", "range", nullptr),
        getKeywordSelector(Ctx, "compare", "options", "range", "locale",
                           nullptr),
        getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet",
                           nullptr),
        getKeywordSelector(Ctx, "initWithFormat",
                           nullptr),
        getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare", nullptr),
        getKeywordSelector(Ctx, "localizedCompare", nullptr),
        getKeywordSelector(Ctx, "localizedStandardCompare", nullptr),
      };
      for (Selector KnownSel : Sels)
        StringSelectors[KnownSel] = 0;
    }
    auto I = StringSelectors.find(S);
    if (I == StringSelectors.end())
      return;
    Arg = I->second;
  } else if (Class == FC_NSArray) {
    Selector S = msg.getSelector();

    if (S.isUnarySelector())
      return;

    if (ArrayWithObjectSel.isNull()) {
      ASTContext &Ctx = C.getASTContext();
      ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject", nullptr);
      AddObjectSel = getKeywordSelector(Ctx, "addObject", nullptr);
      InsertObjectAtIndexSel =
        getKeywordSelector(Ctx, "insertObject", "atIndex", nullptr);
      ReplaceObjectAtIndexWithObjectSel =
        getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject", nullptr);
      SetObjectAtIndexedSubscriptSel =
        getKeywordSelector(Ctx, "setObject", "atIndexedSubscript", nullptr);
      ArrayByAddingObjectSel =
        getKeywordSelector(Ctx, "arrayByAddingObject", nullptr);
    }

    if (S == ArrayWithObjectSel || S == AddObjectSel ||
        S == InsertObjectAtIndexSel || S == ArrayByAddingObjectSel) {
      Arg = 0;
    } else if (S == SetObjectAtIndexedSubscriptSel) {
      Arg = 0;
      CanBeSubscript = true;
    } else if (S == ReplaceObjectAtIndexWithObjectSel) {
      Arg = 1;
    }
  } else if (Class == FC_NSDictionary) {
    Selector S = msg.getSelector();

    if (S.isUnarySelector())
      return;

    if (DictionaryWithObjectForKeySel.isNull()) {
      ASTContext &Ctx = C.getASTContext();
      DictionaryWithObjectForKeySel =
        getKeywordSelector(Ctx, "dictionaryWithObject", "forKey", nullptr);
      SetObjectForKeySel =
        getKeywordSelector(Ctx, "setObject", "forKey", nullptr);
      SetObjectForKeyedSubscriptSel =
        getKeywordSelector(Ctx, "setObject", "forKeyedSubscript", nullptr);
      RemoveObjectForKeySel =
        getKeywordSelector(Ctx, "removeObjectForKey", nullptr);
    }

    if (S == DictionaryWithObjectForKeySel || S == SetObjectForKeySel) {
      Arg = 0;
      warnIfNilArg(C, msg, /* Arg */1, Class);
    } else if (S == SetObjectForKeyedSubscriptSel) {
      CanBeSubscript = true;
      Arg = 0;
      warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
    } else if (S == RemoveObjectForKeySel) {
      Arg = 0;
    }
  }

  // If argument is '0', report a warning.
  if ((Arg != InvalidArgIndex))
    warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
}
void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
                                        CheckerContext &C) const {
  const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
  if (!ID)
    return;

  FoundationClass Class = findKnownClass(ID);

  static const unsigned InvalidArgIndex = UINT_MAX;
  unsigned Arg = InvalidArgIndex;
  bool CanBeSubscript = false;
  
  if (Class == FC_NSString) {
    Selector S = msg.getSelector();
    
    if (S.isUnarySelector())
      return;
    
    // FIXME: This is going to be really slow doing these checks with
    //  lexical comparisons.
    
    std::string NameStr = S.getAsString();
    StringRef Name(NameStr);
    assert(!Name.empty());
    
    // FIXME: Checking for initWithFormat: will not work in most cases
    //  yet because [NSString alloc] returns id, not NSString*.  We will
    //  need support for tracking expected-type information in the analyzer
    //  to find these errors.
    if (Name == "caseInsensitiveCompare:" ||
        Name == "compare:" ||
        Name == "compare:options:" ||
        Name == "compare:options:range:" ||
        Name == "compare:options:range:locale:" ||
        Name == "componentsSeparatedByCharactersInSet:" ||
        Name == "initWithFormat:") {
      Arg = 0;
    }
  } else if (Class == FC_NSArray) {
    Selector S = msg.getSelector();

    if (S.isUnarySelector())
      return;

    if (S.getNameForSlot(0).equals("addObject")) {
      Arg = 0;
    } else if (S.getNameForSlot(0).equals("insertObject") &&
               S.getNameForSlot(1).equals("atIndex")) {
      Arg = 0;
    } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") &&
               S.getNameForSlot(1).equals("withObject")) {
      Arg = 1;
    } else if (S.getNameForSlot(0).equals("setObject") &&
               S.getNameForSlot(1).equals("atIndexedSubscript")) {
      Arg = 0;
      CanBeSubscript = true;
    } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) {
      Arg = 0;
    }
  } else if (Class == FC_NSDictionary) {
    Selector S = msg.getSelector();

    if (S.isUnarySelector())
      return;

    if (S.getNameForSlot(0).equals("dictionaryWithObject") &&
        S.getNameForSlot(1).equals("forKey")) {
      Arg = 0;
      WarnIfNilArg(C, msg, /* Arg */1, Class);
    } else if (S.getNameForSlot(0).equals("setObject") &&
               S.getNameForSlot(1).equals("forKey")) {
      Arg = 0;
      WarnIfNilArg(C, msg, /* Arg */1, Class);
    } else if (S.getNameForSlot(0).equals("setObject") &&
               S.getNameForSlot(1).equals("forKeyedSubscript")) {
      CanBeSubscript = true;
      Arg = 0;
      WarnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
    } else if (S.getNameForSlot(0).equals("removeObjectForKey")) {
      Arg = 0;
    }
  }


  // If argument is '0', report a warning.
  if ((Arg != InvalidArgIndex))
    WarnIfNilArg(C, msg, Arg, Class, CanBeSubscript);

}
Ejemplo n.º 12
0
bool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N,
                                              const ObjCMessageExpr* ME) {

  Selector S = ME->getSelector();

  if (S.isUnarySelector())
    return false;

  // FIXME: This is going to be really slow doing these checks with
  //  lexical comparisons.

  std::string name = S.getAsString();
  assert (!name.empty());
  const char* cstr = &name[0];
  unsigned len = name.size();

  switch (len) {
    default:
      break;
    case 8:
      if (!strcmp(cstr, "compare:"))
        return CheckNilArg(N, 0);

      break;

    case 15:
      // FIXME: Checking for initWithFormat: will not work in most cases
      //  yet because [NSString alloc] returns id, not NSString*.  We will
      //  need support for tracking expected-type information in the analyzer
      //  to find these errors.
      if (!strcmp(cstr, "initWithFormat:"))
        return CheckNilArg(N, 0);

      break;

    case 16:
      if (!strcmp(cstr, "compare:options:"))
        return CheckNilArg(N, 0);

      break;

    case 22:
      if (!strcmp(cstr, "compare:options:range:"))
        return CheckNilArg(N, 0);

      break;

    case 23:

      if (!strcmp(cstr, "caseInsensitiveCompare:"))
        return CheckNilArg(N, 0);

      break;

    case 29:
      if (!strcmp(cstr, "compare:options:range:locale:"))
        return CheckNilArg(N, 0);

      break;

    case 37:
    if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:"))
      return CheckNilArg(N, 0);

    break;
  }

  return false;
}