int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) { if (LHS.getNameKind() != RHS.getNameKind()) return (LHS.getNameKind() < RHS.getNameKind() ? -1 : 1); switch (LHS.getNameKind()) { case DeclarationName::Identifier: { IdentifierInfo *LII = LHS.getAsIdentifierInfo(); IdentifierInfo *RII = RHS.getAsIdentifierInfo(); if (!LII) return RII ? -1 : 0; if (!RII) return 1; return LII->getName().compare(RII->getName()); } case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: { Selector LHSSelector = LHS.getObjCSelector(); Selector RHSSelector = RHS.getObjCSelector(); unsigned LN = LHSSelector.getNumArgs(), RN = RHSSelector.getNumArgs(); for (unsigned I = 0, N = std::min(LN, RN); I != N; ++I) { switch (LHSSelector.getNameForSlot(I).compare( RHSSelector.getNameForSlot(I))) { case -1: return true; case 1: return false; default: break; } } return compareInt(LN, RN); } case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: if (QualTypeOrdering()(LHS.getCXXNameType(), RHS.getCXXNameType())) return -1; if (QualTypeOrdering()(RHS.getCXXNameType(), LHS.getCXXNameType())) return 1; return 0; case DeclarationName::CXXOperatorName: return compareInt(LHS.getCXXOverloadedOperator(), RHS.getCXXOverloadedOperator()); case DeclarationName::CXXLiteralOperatorName: return LHS.getCXXLiteralIdentifier()->getName().compare( RHS.getCXXLiteralIdentifier()->getName()); case DeclarationName::CXXUsingDirective: return 0; } return 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; // 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); }