Index: lib/StaticAnalyzer/Core/PathDiagnostic.cpp =================================================================== --- lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -16,6 +16,7 @@ #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/OperationKinds.h" @@ -1000,11 +1001,49 @@ CalleeCtx->getAnalysisDeclContext()->isBodyAutosynthesized()); } +static void describeTemplateParameters(raw_ostream &Out, + const ArrayRef TAList, + const LangOptions &LO, + StringRef Prefix = StringRef(), + StringRef Postfix = StringRef()); + +static void describeTemplateParameter(raw_ostream &Out, + const TemplateArgument &TArg, + const LangOptions &LO) { + + if (TArg.getKind() == TemplateArgument::ArgKind::Pack) { + describeTemplateParameters(Out, TArg.getPackAsArray(), LO); + } else { + TArg.print(PrintingPolicy(LO), Out); + } +} + +static void describeTemplateParameters(raw_ostream &Out, + const ArrayRef TAList, + const LangOptions &LO, + StringRef Prefix, StringRef Postfix) { + if (TAList.empty()) + return; + + Out << Prefix; + for (int I = 0, Last = TAList.size() - 1; I != Last; ++I) { + describeTemplateParameter(Out, TAList[I], LO); + Out << ", "; + } + describeTemplateParameter(Out, TAList[TAList.size() - 1], LO); + Out << Postfix; +} + static void describeClass(raw_ostream &Out, const CXXRecordDecl *D, StringRef Prefix = StringRef()) { if (!D->getIdentifier()) return; - Out << Prefix << '\'' << *D << '\''; + Out << Prefix << '\'' << *D; + if (const auto T = dyn_cast(D)) + describeTemplateParameters(Out, T->getTemplateArgs().asArray(), + D->getASTContext().getLangOpts(), "<", ">"); + + Out << '\''; } static bool describeCodeDecl(raw_ostream &Out, const Decl *D, @@ -1062,7 +1101,16 @@ return true; } - Out << Prefix << '\'' << cast(*D) << '\''; + Out << Prefix << '\'' << cast(*D); + + // Adding template parameters. + if (const auto FD = dyn_cast(D)) + if (const TemplateArgumentList *TAList = + FD->getTemplateSpecializationArgs()) + describeTemplateParameters(Out, TAList->asArray(), + FD->getASTContext().getLangOpts(), "<", ">"); + + Out << '\''; return true; } Index: test/Analysis/plist-diagnostics-template-function.cpp =================================================================== --- /dev/null +++ test/Analysis/plist-diagnostics-template-function.cpp @@ -0,0 +1,41 @@ +// RUN: %clang_analyze_cc1 -analyzer-output=plist -o %t.plist -std=c++11 -analyzer-checker=core %s +// RUN: FileCheck --input-file=%t.plist %s + +bool ret(); + +template +void f(int i) { + if (ret()) + i = i / (i - 5); +} + +template <> +void f(int i) { + if (ret()) + i = i / (i - 5); +} + +template +void defaultTemplateParameterFunction(int i) { + if (ret()) + int a = 10 / i; +} + +template +void variadicTemplateFunction(int i) { + if (ret()) + int a = 10 / i; +} + +int main() { + f(5); + f(5); + defaultTemplateParameterFunction<>(0); + variadicTemplateFunction(0); +} + +// CHECK: Calling 'f<float>' +// CHECK: Calling 'f<int>' +// CHECK: Calling 'defaultTemplateParameterFunction<0>' +// CHECK: Calling 'variadicTemplateFunction<char, float, double, int *>' + Index: test/Analysis/plist-diagnostics-template-record.cpp =================================================================== --- /dev/null +++ test/Analysis/plist-diagnostics-template-record.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_analyze_cc1 -analyzer-output=plist -o %t.plist -std=c++11 -analyzer-checker=core %s +// RUN: FileCheck --input-file=%t.plist %s + +bool ret(); + +template +struct DivByZero { + int i; + DivByZero(bool b) { + if (ret()) + i = 50 / (b - 1); + } +}; + +template +struct DivByZero { + int i; + DivByZero(bool b) { + if (ret()) + i = 50 / (b - 1); + } +}; + +template +struct DivByZeroVariadic { + int i; + DivByZeroVariadic(bool b) { + if (ret()) + i = 50 / (b - 1); + } +}; + +int main() { + DivByZero a(1); + DivByZero a2(1); + DivByZeroVariadic a3(1); +} + +// CHECK: Calling constructor for 'DivByZero<int, float, double, 0>' +// CHECK: Calling constructor for 'DivByZero<char, float, double, 0>' +// CHECK: Calling constructor for 'DivByZeroVariadic<char, float, double, nullptr_t>' +