diff --git a/cpp/ql/src/Best Practices/Unused Entities/UnusedStaticFunctions.ql b/cpp/ql/src/Best Practices/Unused Entities/UnusedStaticFunctions.ql index 418250d15ac..514cfac9a81 100644 --- a/cpp/ql/src/Best Practices/Unused Entities/UnusedStaticFunctions.ql +++ b/cpp/ql/src/Best Practices/Unused Entities/UnusedStaticFunctions.ql @@ -13,16 +13,32 @@ import cpp +pragma[noinline] +predicate possiblyIncompleteFile(File f) { + exists(Diagnostic d | d.getFile() = f and d.getSeverity() >= 3) +} + predicate immediatelyReachableFunction(Function f) { - not f.isStatic() or - exists(BlockExpr be | be.getFunction() = f) or - f instanceof MemberFunction or - f instanceof TemplateFunction or - f.getFile() instanceof HeaderFile or - f.getAnAttribute().hasName("constructor") or - f.getAnAttribute().hasName("destructor") or - f.getAnAttribute().hasName("used") or + not f.isStatic() + or + exists(BlockExpr be | be.getFunction() = f) + or + f instanceof MemberFunction + or + f instanceof TemplateFunction + or + f.getFile() instanceof HeaderFile + or + f.getAnAttribute().hasName("constructor") + or + f.getAnAttribute().hasName("destructor") + or + f.getAnAttribute().hasName("used") + or f.getAnAttribute().hasName("unused") + or + // a compiler error in the same file suggests we may be missing data + possiblyIncompleteFile(f.getFile()) } predicate immediatelyReachableVariable(Variable v) { diff --git a/cpp/ql/src/change-notes/2022-09-21-unused-static-function.md b/cpp/ql/src/change-notes/2022-09-21-unused-static-function.md new file mode 100644 index 00000000000..80bd25b7179 --- /dev/null +++ b/cpp/ql/src/change-notes/2022-09-21-unused-static-function.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Fixed false positives from the "Unused static function" (`cpp/unused-static-function`) query in files that had errors during compilation. diff --git a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticFunctions/extraction_error.c b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticFunctions/extraction_error.c new file mode 100644 index 00000000000..66eedf743fb --- /dev/null +++ b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticFunctions/extraction_error.c @@ -0,0 +1,15 @@ +// semmle-extractor-options: --expect_errors + +static void my_function1_called() {} // GOOD +static void my_function2_called_after_error() {} // GOOD +static void my_function3_not_called() {} // BAD [NOT DETECTED] + +int main(void) { + my_function1_called(); + +--- compilation stops here because this line is not valid C code --- + + my_function2_called_after_error(); + + return 0; +} diff --git a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticFunctions/unused_static_functions.cpp b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticFunctions/unused_static_functions.cpp index 2984d8f0b1a..c0d83b52a57 100644 --- a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticFunctions/unused_static_functions.cpp +++ b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticFunctions/unused_static_functions.cpp @@ -33,3 +33,16 @@ static void f6(void); static void f5(void) { f6(); } static void f6(void) { f5(); } +// f7 and f8 are reachable from `function_caller` +static int f7() { return 1; } // GOOD +static void f8() { } // GOOD + +void function_caller() +{ + auto my_lambda = []() { + return f7(); + }(); + + f8(); +} +