Index: lib/Analysis/CloneDetection.cpp =================================================================== --- lib/Analysis/CloneDetection.cpp +++ lib/Analysis/CloneDetection.cpp @@ -151,8 +151,24 @@ //--- Calls --------------------------------------------------------------// DEF_ADD_DATA(CallExpr, { // Function pointers don't have a callee and we just skip hashing it. - if (S->getDirectCallee()) + if (S->getDirectCallee()) { + // If the function is a template instantiation, we also need to handle + // the template arguments as they are no included in the qualified name. + if (S->getDirectCallee()->isTemplateInstantiation()) { + auto Args = S->getDirectCallee()->getTemplateSpecializationArgs(); + std::string ArgString; + + // Print all template arguments into ArgString + llvm::raw_string_ostream OS(ArgString); + for (unsigned i = 0; i < Args->size(); ++i) { + Args->get(i).print(Context.getLangOpts(), OS); + } + OS.flush(); + + addData(ArgString); + } addData(S->getDirectCallee()->getQualifiedNameAsString()); + } }) //--- Exceptions ---------------------------------------------------------// Index: test/Analysis/copypaste/call.cpp =================================================================== --- test/Analysis/copypaste/call.cpp +++ test/Analysis/copypaste/call.cpp @@ -34,3 +34,32 @@ return funcPtr(1); return true; } + +// Test that we respect the template arguments of function templates + +template +bool tempFunc() { unsigned i = N; return false; } + +bool fooTemp1(int x) { + if (x > 0) + return false; + else if (x < 0) + return tempFunc(); + return true; +} + +bool fooTemp2(int x) { + if (x > 0) + return false; + else if (x < 0) + return tempFunc(); + return true; +} + +bool fooTemp3(int x) { + if (x > 0) + return false; + else if (x < 0) + return tempFunc(); + return true; +}