diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 3020ab54d0b7..2faf62e3fcc7 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -265,19 +265,8 @@ public: else assert(Mode == (AM_Syntax | AM_Path) && "Unexpected mode!"); - llvm::errs() << ": " << Loc.getFilename(); - if (isa(D) || isa(D)) { - const NamedDecl *ND = cast(D); - llvm::errs() << ' ' << ND->getQualifiedNameAsString() << '\n'; - } - else if (isa(D)) { - llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:" - << Loc.getColumn() << '\n'; - } - else if (const ObjCMethodDecl *MD = dyn_cast(D)) { - Selector S = MD->getSelector(); - llvm::errs() << ' ' << S.getAsString(); - } + llvm::errs() << ": " << Loc.getFilename() << ' ' + << getFunctionName(D) << '\n'; } } @@ -377,6 +366,7 @@ public: private: void storeTopLevelDecls(DeclGroupRef DG); + std::string getFunctionName(const Decl *D); /// \brief Check if we should skip (not analyze) the given function. AnalysisMode getModeForDecl(Decl *D, AnalysisMode Mode); @@ -568,16 +558,64 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { } -static std::string getFunctionName(const Decl *D) { - if (const ObjCMethodDecl *ID = dyn_cast(D)) { - return ID->getSelector().getAsString(); +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 << ((const NamedDecl *)OCD)->getIdentifier()->getNameStart() << '(' + << OCD->getIdentifier()->getNameStart() << ')'; + } else if (isa(DC)) { + // We can extract the type of the class from the self pointer. + if (ImplicitParamDecl *SelfDecl = OMD->getSelfDecl()) { + QualType ClassTy = + cast(SelfDecl->getType())->getPointeeType(); + ClassTy.print(OS, PrintingPolicy(LangOptions())); + } + } + OS << ' ' << OMD->getSelector().getAsString() << ']'; + } - if (const FunctionDecl *ND = dyn_cast(D)) { - IdentifierInfo *II = ND->getIdentifier(); - if (II) - return II->getName(); - } - return ""; + + return OS.str(); } AnalysisConsumer::AnalysisMode diff --git a/clang/test/Analysis/analyzeOneFunction.m b/clang/test/Analysis/analyzeOneFunction.m index 1ff2fc8fe8a3..e70b2d7d5fbc 100644 --- a/clang/test/Analysis/analyzeOneFunction.m +++ b/clang/test/Analysis/analyzeOneFunction.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyze-function="myMethodWithY:withX:" -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -verify %s +// RUN: %clang_cc1 -analyze -analyze-function="-[Test1 myMethodWithY:withX:]" -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -verify %s typedef signed char BOOL; typedef unsigned int NSUInteger; diff --git a/clang/test/Analysis/analyze_display_progress.cpp b/clang/test/Analysis/analyze_display_progress.cpp deleted file mode 100644 index c84ab63de482..000000000000 --- a/clang/test/Analysis/analyze_display_progress.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// RUN: %clang_cc1 -analyze -analyzer-display-progress %s 2>&1 | FileCheck %s - -void f() {}; -void g() {}; -void h() {} - -struct SomeStruct { - void f() {} -}; - -struct SomeOtherStruct { - void f() {} -}; - -namespace ns { - struct SomeStruct { - void f() {} - }; -} - -// CHECK: analyze_display_progress.cpp f -// CHECK: analyze_display_progress.cpp g -// CHECK: analyze_display_progress.cpp h -// CHECK: analyze_display_progress.cpp SomeStruct::f -// CHECK: analyze_display_progress.cpp SomeOtherStruct::f -// CHECK: analyze_display_progress.cpp ns::SomeStruct::f diff --git a/clang/test/Analysis/analyzer-display-progress.cpp b/clang/test/Analysis/analyzer-display-progress.cpp new file mode 100644 index 000000000000..5d9f5e5b28f0 --- /dev/null +++ b/clang/test/Analysis/analyzer-display-progress.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -analyze -analyzer-display-progress %s 2>&1 | FileCheck %s + +void f() {}; +void g() {}; +void h() {} + +struct SomeStruct { + void f() {} +}; + +struct SomeOtherStruct { + void f() {} +}; + +namespace ns { + struct SomeStruct { + void f(int) {} + void f(float, ::SomeStruct) {} + void f(float, SomeStruct) {} + }; +} + +// CHECK: analyzer-display-progress.cpp f() +// CHECK: analyzer-display-progress.cpp g() +// CHECK: analyzer-display-progress.cpp h() +// CHECK: analyzer-display-progress.cpp SomeStruct::f() +// CHECK: analyzer-display-progress.cpp SomeOtherStruct::f() +// CHECK: analyzer-display-progress.cpp ns::SomeStruct::f(int) +// CHECK: analyzer-display-progress.cpp ns::SomeStruct::f(float, ::SomeStruct) +// CHECK: analyzer-display-progress.cpp ns::SomeStruct::f(float, struct ns::SomeStruct) diff --git a/clang/test/Analysis/analyzer-display-progress.m b/clang/test/Analysis/analyzer-display-progress.m new file mode 100644 index 000000000000..cc43cf36d60e --- /dev/null +++ b/clang/test/Analysis/analyzer-display-progress.m @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -fblocks -analyze -analyzer-display-progress %s 2>&1 | FileCheck %s + +#include "Inputs/system-header-simulator-objc.h" + +static void f() {} + +@interface I: NSObject +-(void)instanceMethod:(int)arg1 with:(int)arg2; ++(void)classMethod; +@end + +@implementation I +-(void)instanceMethod:(int)arg1 with:(int)arg2 {} ++(void)classMethod {} +@end + +void g(I *i, int x, int y) { + [I classMethod]; + [i instanceMethod: x with: y]; + + void (^block)(void); + block = ^{}; + block(); +} + +// CHECK: analyzer-display-progress.m f +// CHECK: analyzer-display-progress.m -[I instanceMethod:with:] +// CHECK: analyzer-display-progress.m +[I classMethod] +// CHECK: analyzer-display-progress.m g +// CHECK: analyzer-display-progress.m block (line: 22, col: 11)