#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"
CalleeCtx->getAnalysisDeclContext()->isBodyAutosynthesized());
}
+static void describeTemplateParameters(raw_ostream &Out,
+ const ArrayRef<TemplateArgument> 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<TemplateArgument> 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<ClassTemplateSpecializationDecl>(D))
+ describeTemplateParameters(Out, T->getTemplateArgs().asArray(),
+ D->getASTContext().getLangOpts(), "<", ">");
+
+ Out << '\'';
}
static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
return true;
}
- Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\'';
+ Out << Prefix << '\'' << cast<NamedDecl>(*D);
+
+ // Adding template parameters.
+ if (const auto FD = dyn_cast<FunctionDecl>(D))
+ if (const TemplateArgumentList *TAList =
+ FD->getTemplateSpecializationArgs())
+ describeTemplateParameters(Out, TAList->asArray(),
+ FD->getASTContext().getLangOpts(), "<", ">");
+
+ Out << '\'';
return true;
}
--- /dev/null
+// 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 <class T>
+void f(int i) {
+ if (ret())
+ i = i / (i - 5);
+}
+
+template <>
+void f<int>(int i) {
+ if (ret())
+ i = i / (i - 5);
+}
+
+template <int N = 0>
+void defaultTemplateParameterFunction(int i) {
+ if (ret())
+ int a = 10 / i;
+}
+
+template <typename... Args>
+void variadicTemplateFunction(int i) {
+ if (ret())
+ int a = 10 / i;
+}
+
+int main() {
+ f<int>(5);
+ f<float>(5);
+ defaultTemplateParameterFunction<>(0);
+ variadicTemplateFunction<char, float, double, int *>(0);
+}
+
+// CHECK: <string>Calling 'f<float>'</string>
+// CHECK: <string>Calling 'f<int>'</string>
+// CHECK: <string>Calling 'defaultTemplateParameterFunction<0>'</string>
+// CHECK: <string>Calling 'variadicTemplateFunction<char, float, double, int *>'</string>
+
--- /dev/null
+// 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 <class A, class B, class C, int N>
+struct DivByZero {
+ int i;
+ DivByZero(bool b) {
+ if (ret())
+ i = 50 / (b - 1);
+ }
+};
+
+template <class B, class C, int N>
+struct DivByZero<char, B, C, N> {
+ int i;
+ DivByZero(bool b) {
+ if (ret())
+ i = 50 / (b - 1);
+ }
+};
+
+template <typename... Args>
+struct DivByZeroVariadic {
+ int i;
+ DivByZeroVariadic(bool b) {
+ if (ret())
+ i = 50 / (b - 1);
+ }
+};
+
+int main() {
+ DivByZero<int, float, double, 0> a(1);
+ DivByZero<char, float, double, 0> a2(1);
+ DivByZeroVariadic<char, float, double, decltype(nullptr)> a3(1);
+}
+
+// CHECK: <string>Calling constructor for 'DivByZero<int, float, double, 0>'</string>
+// CHECK: <string>Calling constructor for 'DivByZero<char, float, double, 0>'</string>
+// CHECK: <string>Calling constructor for 'DivByZeroVariadic<char, float, double, nullptr_t>'</string>
+