From: Kristof Umann Date: Fri, 25 May 2018 13:18:38 +0000 (+0000) Subject: [analyzer] Added template argument lists to the Pathdiagnostic output X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=555aa337cb09d70f8ad0caabfe5244818a62f456;p=clang [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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@333275 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index dcb197c9ca..4da966f644 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/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 @@ void PathDiagnosticCallPiece::setCallee(const CallEnter &CE, 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 @@ static bool describeCodeDecl(raw_ostream &Out, const Decl *D, 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; } diff --git a/test/Analysis/plist-diagnostics-template-function.cpp b/test/Analysis/plist-diagnostics-template-function.cpp new file mode 100644 index 0000000000..1f44a789cc --- /dev/null +++ b/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 *>' + diff --git a/test/Analysis/plist-diagnostics-template-record.cpp b/test/Analysis/plist-diagnostics-template-record.cpp new file mode 100644 index 0000000000..ffd6d03088 --- /dev/null +++ b/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>' +