forked from OSchip/llvm-project
[analyzer] Change -analyze-function to accept qualified names.
Both -analyze-function and -analyzer-display-progress now share the same convention for naming functions, which allows discriminating between methods with the same name in different classes, C++ overloads, and also presents Objective-C instance and class methods in the convenient notation. This also allows looking up the name for the particular function you're trying to restrict analysis to in the -analyzer-display-progress output, in case it was not instantly obvious. Differential Revision: https://reviews.llvm.org/D22856 llvm-svn: 278018
This commit is contained in:
parent
0aa29532b7
commit
6a76a1639f
|
@ -265,19 +265,8 @@ public:
|
|||
else
|
||||
assert(Mode == (AM_Syntax | AM_Path) && "Unexpected mode!");
|
||||
|
||||
llvm::errs() << ": " << Loc.getFilename();
|
||||
if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
|
||||
const NamedDecl *ND = cast<NamedDecl>(D);
|
||||
llvm::errs() << ' ' << ND->getQualifiedNameAsString() << '\n';
|
||||
}
|
||||
else if (isa<BlockDecl>(D)) {
|
||||
llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:"
|
||||
<< Loc.getColumn() << '\n';
|
||||
}
|
||||
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(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<ObjCMethodDecl>(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<FunctionDecl>(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<BlockDecl>(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<ObjCMethodDecl>(D)) {
|
||||
|
||||
// FIXME: copy-pasted from CGDebugInfo.cpp.
|
||||
OS << (OMD->isInstanceMethod() ? '-' : '+') << '[';
|
||||
const DeclContext *DC = OMD->getDeclContext();
|
||||
if (const auto *OID = dyn_cast<ObjCImplementationDecl>(DC)) {
|
||||
OS << OID->getName();
|
||||
} else if (const auto *OID = dyn_cast<ObjCInterfaceDecl>(DC)) {
|
||||
OS << OID->getName();
|
||||
} else if (const auto *OC = dyn_cast<ObjCCategoryDecl>(DC)) {
|
||||
if (OC->IsClassExtension()) {
|
||||
OS << OC->getClassInterface()->getName();
|
||||
} else {
|
||||
OS << OC->getIdentifier()->getNameStart() << '('
|
||||
<< OC->getIdentifier()->getNameStart() << ')';
|
||||
}
|
||||
} else if (const auto *OCD = dyn_cast<ObjCCategoryImplDecl>(DC)) {
|
||||
OS << ((const NamedDecl *)OCD)->getIdentifier()->getNameStart() << '('
|
||||
<< OCD->getIdentifier()->getNameStart() << ')';
|
||||
} else if (isa<ObjCProtocolDecl>(DC)) {
|
||||
// We can extract the type of the class from the self pointer.
|
||||
if (ImplicitParamDecl *SelfDecl = OMD->getSelfDecl()) {
|
||||
QualType ClassTy =
|
||||
cast<ObjCObjectPointerType>(SelfDecl->getType())->getPointeeType();
|
||||
ClassTy.print(OS, PrintingPolicy(LangOptions()));
|
||||
}
|
||||
}
|
||||
OS << ' ' << OMD->getSelector().getAsString() << ']';
|
||||
|
||||
}
|
||||
if (const FunctionDecl *ND = dyn_cast<FunctionDecl>(D)) {
|
||||
IdentifierInfo *II = ND->getIdentifier();
|
||||
if (II)
|
||||
return II->getName();
|
||||
}
|
||||
return "";
|
||||
|
||||
return OS.str();
|
||||
}
|
||||
|
||||
AnalysisConsumer::AnalysisMode
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
Loading…
Reference in New Issue