}
};
+enum CallDescriptionFlags : int {
+ /// Describes a C standard function that is sometimes implemented as a macro
+ /// that expands to a compiler builtin with some __builtin prefix.
+ /// The builtin may as well have a few extra arguments on top of the requested
+ /// number of arguments.
+ CDF_MaybeBuiltin = 1 << 0,
+};
+
/// This class represents a description of a function call using the number of
/// arguments and the name of the function.
class CallDescription {
// e.g. "{a, b}" represent the qualified names, like "a::b".
std::vector<const char *> QualifiedName;
Optional<unsigned> RequiredArgs;
+ int Flags;
public:
/// Constructs a CallDescription object.
/// @param RequiredArgs The number of arguments that is expected to match a
/// call. Omit this parameter to match every occurrence of call with a given
/// name regardless the number of arguments.
+ CallDescription(int Flags, ArrayRef<const char *> QualifiedName,
+ Optional<unsigned> RequiredArgs = None)
+ : QualifiedName(QualifiedName), RequiredArgs(RequiredArgs),
+ Flags(Flags) {}
+
+ /// Construct a CallDescription with default flags.
CallDescription(ArrayRef<const char *> QualifiedName,
Optional<unsigned> RequiredArgs = None)
- : QualifiedName(QualifiedName), RequiredArgs(RequiredArgs) {}
+ : CallDescription(0, QualifiedName, RequiredArgs) {}
/// Get the name of the function that this object matches.
StringRef getFunctionName() const { return QualifiedName.back(); }
// FIXME: Add ObjC Message support.
if (getKind() == CE_ObjCMessage)
return false;
+
+ const IdentifierInfo *II = getCalleeIdentifier();
+ if (!II)
+ return false;
+ const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(getDecl());
+ if (!FD)
+ return false;
+
+ if (CD.Flags & CDF_MaybeBuiltin) {
+ return CheckerContext::isCLibraryFunction(FD, CD.getFunctionName()) &&
+ (!CD.RequiredArgs || CD.RequiredArgs <= getNumArgs());
+ }
+
if (!CD.IsLookupDone) {
CD.IsLookupDone = true;
CD.II = &getState()->getStateManager().getContext().Idents.get(
CD.getFunctionName());
}
- const IdentifierInfo *II = getCalleeIdentifier();
- if (!II || II != CD.II)
+
+ if (II != CD.II)
return false;
- const Decl *D = getDecl();
// If CallDescription provides prefix names, use them to improve matching
// accuracy.
- if (CD.QualifiedName.size() > 1 && D) {
- const DeclContext *Ctx = D->getDeclContext();
+ if (CD.QualifiedName.size() > 1 && FD) {
+ const DeclContext *Ctx = FD->getDeclContext();
// See if we'll be able to match them all.
size_t NumUnmatched = CD.QualifiedName.size() - 1;
for (; Ctx && isa<NamedDecl>(Ctx); Ctx = Ctx->getParent()) {
{{{"bar", "foo"}}, false},
{{"foo"}, true},
}), "void foo(); struct bar { void foo(); }; void test() { foo(); }"));
+
+ // Test CDF_MaybeBuiltin - a flag that allows matching weird builtins.
+ EXPECT_TRUE(tooling::runToolOnCode(
+ new CallDescriptionAction({
+ {{"memset", 3}, false},
+ {{CDF_MaybeBuiltin, "memset", 3}, true}
+ }),
+ "void foo() {"
+ " int x;"
+ " __builtin___memset_chk(&x, 0, sizeof(x),"
+ " __builtin_object_size(&x, 0));"
+ "}"));
}
} // namespace