diff --git a/src/checks/manuallevel/jnisignatures.h b/src/checks/manuallevel/jnisignatures.h --- a/src/checks/manuallevel/jnisignatures.h +++ b/src/checks/manuallevel/jnisignatures.h @@ -42,10 +42,9 @@ void VisitStmt(clang::Stmt *) override; private: template - void checkArgAt(T *call, unsigned int index); + void checkArgAt(T *call, unsigned int index, const regex &expr, const std::string &errorMessage); void checkConstructorCall(clang::Stmt *stm); void checkFunctionCall(clang::Stmt *stm); - bool functionShouldBeChecked(clang::FunctionDecl *funDecl); }; #endif diff --git a/src/checks/manuallevel/jnisignatures.cpp b/src/checks/manuallevel/jnisignatures.cpp --- a/src/checks/manuallevel/jnisignatures.cpp +++ b/src/checks/manuallevel/jnisignatures.cpp @@ -48,21 +48,25 @@ using namespace clang; using namespace std; +static const regex methodSignatureRegex("\\((\\[?([ZBCSIJFD]|L([a-zA-Z]+\\/)*[a-zA-Z]+;))*\\)\\[?([ZBCSIJFD]|L([a-zA-Z]+\\/)*[a-zA-Z]+;|V)"); + +static const regex classNameRegex("([a-zA-Z]+\\/)*[a-zA-Z]+"); + +static const regex methodNameRegex("[a-zA-Z]+"); + JniSignatures::JniSignatures(const std::string &name, ClazyContext *context) : CheckBase(name, context, Option_CanIgnoreIncludes) { } -bool checkSignature(std::string signature) +bool checkSignature(std::string signature, const regex &expr) { - static regex rx("\\((\\[?([ZBCSIJFD]|L([a-zA-Z]+\\/)*[a-zA-Z]+;))*\\)\\[?([ZBCSIJFD]|L([a-zA-Z]+\\/)*[a-zA-Z]+;|V)"); - smatch match; - return regex_match(signature, match, rx); + return regex_match(signature, match, expr); } template -void JniSignatures::checkArgAt(T *call, unsigned int index) +void JniSignatures::checkArgAt(T *call, unsigned int index, const regex &expr, const std::string &errorMessage) { if (call->getNumArgs() < index + 1) return; @@ -77,27 +81,13 @@ const std::string signature = stringLiteral->getString().str(); - const bool valid = checkSignature(signature); + const bool valid = checkSignature(signature, expr); if (!valid) { - emitWarning(call, "Invalid method signature: '" + signature + "'"); + emitWarning(call, errorMessage + ": '" + signature + "'"); } } -bool JniSignatures::functionShouldBeChecked(FunctionDecl *funDecl) -{ - const std::string qualifiedName = funDecl->getQualifiedNameAsString(); - if (!clazy::startsWith(qualifiedName, "QAndroidJniObject::")) { - return false; - } - - const std::string name = clazy::name(funDecl); - return name == "callObjectMethod" - || name == "callMethod" - || name == "callStaticObjectMethod" - || name == "callStaticMethod"; -} - void JniSignatures::checkFunctionCall(Stmt *stm) { auto callExpr = dyn_cast(stm); @@ -108,11 +98,21 @@ return; } - if (!functionShouldBeChecked(funDecl)) { + const std::string qualifiedName = funDecl->getQualifiedNameAsString(); + if (!clazy::startsWith(qualifiedName, "QAndroidJniObject::")) { return; } - checkArgAt(callExpr, 1); + const std::string name = clazy::name(funDecl); + + if (name == "callObjectMethod" || name == "callMethod") { + checkArgAt(callExpr, 0, methodNameRegex, "Invalid method name"); + checkArgAt(callExpr, 1, methodSignatureRegex, "Invalid method signature"); + } else if (name == "callStaticObjectMethod" || name == "callStaticMethod") { + checkArgAt(callExpr, 0, classNameRegex, "Invalid class name"); + checkArgAt(callExpr, 1, methodNameRegex, "Invalid method name"); + checkArgAt(callExpr, 2, methodSignatureRegex, "Invalid method signature"); + } } void JniSignatures::checkConstructorCall(Stmt *stm) @@ -128,7 +128,8 @@ return; } - checkArgAt(constructExpr, 1); + checkArgAt(constructExpr, 0, classNameRegex, "Invalid class name"); + checkArgAt(constructExpr, 1, methodSignatureRegex, "Invalid constructor signature"); } void JniSignatures::VisitStmt(Stmt *stm) diff --git a/tests/jni-signatures/main.cpp b/tests/jni-signatures/main.cpp --- a/tests/jni-signatures/main.cpp +++ b/tests/jni-signatures/main.cpp @@ -1,35 +1,54 @@ +#define jclass int +#define jint int +#define jstring int + // Crude approximation of #include so we don't need QtAndroidExtras installed class QAndroidJniObject { public: QAndroidJniObject(const char *className, const char *signature); + QAndroidJniObject(jclass theClass, const char *signature); template void callObjectMethod(const char *methodName, const char *signature); template void callMethod(const char *methodName, const char *signature); template - static void callStaticMethod(const char *methodName, const char *signature); + static void callStaticMethod(const char *className, const char *methodName, const char *signature); template - static void callStaticObjectMethod(const char *methodName, const char *signature); + static void callStaticObjectMethod(const char *className, const char *methodName, const char *signature); + +}; + +namespace QtAndroid { + void androidActivity(); }; int main() { - QAndroidJniObject obj("java/lang/String", "("); + + QAndroidJniObject obj("/java/lang/String", "("); + + jclass foo = 1; + QAndroidJniObject obj2(foo, "()V"); + obj.callObjectMethod("someMethod", "()V"); obj.callObjectMethod("someMethod", "(III)V"); obj.callObjectMethod("someMethod", "(III"); - obj.callMethod("someMethod", "()V"); - obj.callMethod("someMethod", "(III)V"); - obj.callMethod("someMethod", "()Ljava/lang/String"); + obj.callMethod("someMethod", "()V"); + obj.callMethod("someMethod", "(III)V"); + obj.callMethod("someMethod", "()Ljava/lang/String"); + + QAndroidJniObject::callStaticMethod("someClass;", "someMethod", "()Ljava/lang/String"); + + QAndroidJniObject::callStaticObjectMethod("someClass", "someOtherMethod", "(II)"); - QAndroidJniObject::callStaticMethod("someMethod", "()Ljava/lang/String"); + obj.callObjectMethod("className;", "toString"); - QAndroidJniObject::callStaticObjectMethod("someOtherMethod", "(II)"); + QtAndroid::androidActivity(); } diff --git a/tests/jni-signatures/main.cpp.expected b/tests/jni-signatures/main.cpp.expected --- a/tests/jni-signatures/main.cpp.expected +++ b/tests/jni-signatures/main.cpp.expected @@ -1,5 +1,9 @@ -jni-signatures/main.cpp:23:23: warning: Invalid method signature: '(' [-Wclazy-jni-signatures] -jni-signatures/main.cpp:26:5: warning: Invalid method signature: '(III' [-Wclazy-jni-signatures] -jni-signatures/main.cpp:30:5: warning: Invalid method signature: '()Ljava/lang/String' [-Wclazy-jni-signatures] -jni-signatures/main.cpp:32:5: warning: Invalid method signature: '()Ljava/lang/String' [-Wclazy-jni-signatures] -jni-signatures/main.cpp:34:5: warning: Invalid method signature: '(II)' [-Wclazy-jni-signatures] +jni-signatures/main.cpp:34:23: warning: Invalid class name: '/java/lang/String' [-Wclazy-jni-signatures] +jni-signatures/main.cpp:34:23: warning: Invalid constructor signature: '(' [-Wclazy-jni-signatures] +jni-signatures/main.cpp:41:5: warning: Invalid method signature: '(III' [-Wclazy-jni-signatures] +jni-signatures/main.cpp:45:5: warning: Invalid method signature: '()Ljava/lang/String' [-Wclazy-jni-signatures] +jni-signatures/main.cpp:47:5: warning: Invalid class name: 'someClass;' [-Wclazy-jni-signatures] +jni-signatures/main.cpp:47:5: warning: Invalid method signature: '()Ljava/lang/String' [-Wclazy-jni-signatures] +jni-signatures/main.cpp:49:5: warning: Invalid method signature: '(II)' [-Wclazy-jni-signatures] +jni-signatures/main.cpp:51:5: warning: Invalid method name: 'className;' [-Wclazy-jni-signatures] +jni-signatures/main.cpp:51:5: warning: Invalid method signature: 'toString' [-Wclazy-jni-signatures]