diff --git a/clang/include/clang/Analysis/AnalysisDeclContext.h b/clang/include/clang/Analysis/AnalysisDeclContext.h --- a/clang/include/clang/Analysis/AnalysisDeclContext.h +++ b/clang/include/clang/Analysis/AnalysisDeclContext.h @@ -200,6 +200,8 @@ /// \returns Whether the root namespace of \p D is the \c std C++ namespace. static bool isInStdNamespace(const Decl *D); + static std::string getFunctionName(const Decl *D); + private: std::unique_ptr &getAnalysisImpl(const void *tag); diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp --- a/clang/lib/Analysis/AnalysisDeclContext.cpp +++ b/clang/lib/Analysis/AnalysisDeclContext.cpp @@ -337,6 +337,59 @@ return ND->isStdNamespace(); } +std::string AnalysisDeclContext::getFunctionName(const Decl *D) { + std::string Str; + llvm::raw_string_ostream OS(Str); + const ASTContext &Ctx = D->getASTContext(); + + if (const FunctionDecl *FD = dyn_cast(D)) { + OS << FD->getQualifiedNameAsString(); + + // In C++, there are overloads. + + if (Ctx.getLangOpts().CPlusPlus) { + OS << '('; + for (const auto &P : FD->parameters()) { + if (P != *FD->param_begin()) + OS << ", "; + OS << P->getType().getAsString(); + } + OS << ')'; + } + + } else if (isa(D)) { + PresumedLoc Loc = Ctx.getSourceManager().getPresumedLoc(D->getLocation()); + + if (Loc.isValid()) { + OS << "block (line: " << Loc.getLine() << ", col: " << Loc.getColumn() + << ')'; + } + + } else if (const ObjCMethodDecl *OMD = dyn_cast(D)) { + + // FIXME: copy-pasted from CGDebugInfo.cpp. + OS << (OMD->isInstanceMethod() ? '-' : '+') << '['; + const DeclContext *DC = OMD->getDeclContext(); + if (const auto *OID = dyn_cast(DC)) { + OS << OID->getName(); + } else if (const auto *OID = dyn_cast(DC)) { + OS << OID->getName(); + } else if (const auto *OC = dyn_cast(DC)) { + if (OC->IsClassExtension()) { + OS << OC->getClassInterface()->getName(); + } else { + OS << OC->getIdentifier()->getNameStart() << '(' + << OC->getIdentifier()->getNameStart() << ')'; + } + } else if (const auto *OCD = dyn_cast(DC)) { + OS << OCD->getClassInterface()->getName() << '(' << OCD->getName() << ')'; + } + OS << ' ' << OMD->getSelector().getAsString() << ']'; + } + + return OS.str(); +} + LocationContextManager &AnalysisDeclContext::getLocationContextManager() { assert( ADCMgr && @@ -456,7 +509,7 @@ Out << "\t#" << Frame << ' '; ++Frame; if (const auto *D = dyn_cast(LCtx->getDecl())) - Out << "Calling " << D->getQualifiedNameAsString(); + Out << "Calling " << AnalysisDeclContext::getFunctionName(D); else Out << "Calling anonymous code"; if (const Stmt *S = cast(LCtx)->getCallSite()) { diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -209,8 +209,8 @@ } else assert(Mode == (AM_Syntax | AM_Path) && "Unexpected mode!"); - llvm::errs() << ": " << Loc.getFilename() << ' ' << getFunctionName(D) - << '\n'; + llvm::errs() << ": " << Loc.getFilename() << ' ' + << AnalysisDeclContext::getFunctionName(D) << '\n'; } } @@ -568,63 +568,10 @@ Mgr.reset(); } -std::string AnalysisConsumer::getFunctionName(const Decl *D) { - std::string Str; - llvm::raw_string_ostream OS(Str); - - if (const FunctionDecl *FD = dyn_cast(D)) { - OS << FD->getQualifiedNameAsString(); - - // In C++, there are overloads. - if (Ctx->getLangOpts().CPlusPlus) { - OS << '('; - for (const auto &P : FD->parameters()) { - if (P != *FD->param_begin()) - OS << ", "; - OS << P->getType().getAsString(); - } - OS << ')'; - } - - } else if (isa(D)) { - PresumedLoc Loc = Ctx->getSourceManager().getPresumedLoc(D->getLocation()); - - if (Loc.isValid()) { - OS << "block (line: " << Loc.getLine() << ", col: " << Loc.getColumn() - << ')'; - } - - } else if (const ObjCMethodDecl *OMD = dyn_cast(D)) { - - // FIXME: copy-pasted from CGDebugInfo.cpp. - OS << (OMD->isInstanceMethod() ? '-' : '+') << '['; - const DeclContext *DC = OMD->getDeclContext(); - if (const auto *OID = dyn_cast(DC)) { - OS << OID->getName(); - } else if (const auto *OID = dyn_cast(DC)) { - OS << OID->getName(); - } else if (const auto *OC = dyn_cast(DC)) { - if (OC->IsClassExtension()) { - OS << OC->getClassInterface()->getName(); - } else { - OS << OC->getIdentifier()->getNameStart() << '(' - << OC->getIdentifier()->getNameStart() << ')'; - } - } else if (const auto *OCD = dyn_cast(DC)) { - OS << OCD->getClassInterface()->getName() << '(' - << OCD->getName() << ')'; - } - OS << ' ' << OMD->getSelector().getAsString() << ']'; - - } - - return OS.str(); -} - AnalysisConsumer::AnalysisMode AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) { if (!Opts->AnalyzeSpecificFunction.empty() && - getFunctionName(D) != Opts->AnalyzeSpecificFunction) + AnalysisDeclContext::getFunctionName(D) != Opts->AnalyzeSpecificFunction) return AM_None; // Unless -analyze-all is specified, treat decls differently depending on diff --git a/clang/test/Analysis/crash-trace.c b/clang/test/Analysis/crash-trace.c --- a/clang/test/Analysis/crash-trace.c +++ b/clang/test/Analysis/crash-trace.c @@ -1,4 +1,7 @@ -// RUN: not --crash %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection %s 2>&1 | FileCheck %s +// RUN: not --crash %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection \ +// RUN: -x c %s 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-C-ONLY +// RUN: not --crash %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection \ +// RUN: -x c++ %s 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-CXX-ONLY // REQUIRES: crash-recovery // Stack traces require back traces. @@ -6,17 +9,22 @@ void clang_analyzer_crash(void); -void inlined() { +void inlined(int x, float y) { clang_analyzer_crash(); } void test() { - inlined(); + inlined(0, 0); } -// CHECK: 0. Program arguments: {{.*}}clang -// CHECK-NEXT: 1. parser at end of file -// CHECK-NEXT: 2. While analyzing stack: -// CHECK-NEXT: #0 Calling inlined at line 14 -// CHECK-NEXT: #1 Calling test -// CHECK-NEXT: 3. {{.*}}crash-trace.c:{{[0-9]+}}:3: Error evaluating statement +// CHECK: 0. Program arguments: {{.*}}clang +// CHECK-NEXT: 1. parser at end of file +// CHECK-NEXT: 2. While analyzing stack: +// +// CHECK-C-ONLY-NEXT: #0 Calling inlined at line 17 +// CHECK-C-ONLY-NEXT: #1 Calling test +// +// CHECK-CXX-ONLY-NEXT: #0 Calling inlined(int, float) at line 17 +// CHECK-CXX-ONLY-NEXT: #1 Calling test() +// +// CHECK-NEXT: 3. {{.*}}crash-trace.c:{{[0-9]+}}:3: Error evaluating statement