[analyzer] Added template argument lists to the Pathdiagnostic output

Because template parameter lists were not displayed
in the plist output, it was difficult to decide in
some cases whether a given checker found a true or a
false positive. This patch aims to correct this.

Differential Revision: https://reviews.llvm.org/D46933

llvm-svn: 333275
This commit is contained in:
Kristof Umann 2018-05-25 13:18:38 +00:00
parent 05b6a53340
commit 3ea7442bd6
3 changed files with 133 additions and 2 deletions

View File

@ -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 @@ void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
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,
@ -1062,7 +1101,16 @@ 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;
}

View File

@ -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 <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 &apos;f&lt;float&gt;&apos;</string>
// CHECK: <string>Calling &apos;f&lt;int&gt;&apos;</string>
// CHECK: <string>Calling &apos;defaultTemplateParameterFunction&lt;0&gt;&apos;</string>
// CHECK: <string>Calling &apos;variadicTemplateFunction&lt;char, float, double, int *&gt;&apos;</string>

View File

@ -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 <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 &apos;DivByZero&lt;int, float, double, 0&gt;&apos;</string>
// CHECK: <string>Calling constructor for &apos;DivByZero&lt;char, float, double, 0&gt;&apos;</string>
// CHECK: <string>Calling constructor for &apos;DivByZeroVariadic&lt;char, float, double, nullptr_t&gt;&apos;</string>