forked from OSchip/llvm-project
[analyzer] Change inlining policy to inline small functions when reanalyzing ObjC methods as top level.
This allows us to better reason about(inline) small wrapper functions. llvm-svn: 178063
This commit is contained in:
parent
ea47959c2f
commit
b13d21b6e1
|
|
@ -48,13 +48,13 @@ class CXXConstructorCall;
|
||||||
|
|
||||||
class ExprEngine : public SubEngine {
|
class ExprEngine : public SubEngine {
|
||||||
public:
|
public:
|
||||||
/// The modes of inlining.
|
/// The modes of inlining, which override the default analysis-wide settings.
|
||||||
enum InliningModes {
|
enum InliningModes {
|
||||||
/// Do not inline any of the callees.
|
/// Follow the default settings for inlining callees.
|
||||||
Inline_None = 0,
|
Inline_Regular = 0,
|
||||||
/// Inline all callees.
|
/// Do minimal inlining of callees.
|
||||||
Inline_All = 0x1
|
Inline_Minimal = 0x1
|
||||||
} ;
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AnalysisManager &AMgr;
|
AnalysisManager &AMgr;
|
||||||
|
|
|
||||||
|
|
@ -683,7 +683,7 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D,
|
||||||
if (CalleeADC->isBodyAutosynthesized())
|
if (CalleeADC->isBodyAutosynthesized())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (HowToInline == Inline_None)
|
if (!AMgr.shouldInlineCall())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check if we should inline a call based on its kind.
|
// Check if we should inline a call based on its kind.
|
||||||
|
|
@ -745,6 +745,12 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D,
|
||||||
NumReachedInlineCountMax++;
|
NumReachedInlineCountMax++;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (HowToInline == Inline_Minimal &&
|
||||||
|
(CalleeCFG->getNumBlockIDs() > Opts.getAlwaysInlineSize()
|
||||||
|
|| IsRecursive))
|
||||||
|
return false;
|
||||||
|
|
||||||
Engine.FunctionSummaries->bumpNumTimesInlined(D);
|
Engine.FunctionSummaries->bumpNumTimesInlined(D);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -234,11 +234,11 @@ public:
|
||||||
else if (Mode == AM_Path) {
|
else if (Mode == AM_Path) {
|
||||||
llvm::errs() << " (Path, ";
|
llvm::errs() << " (Path, ";
|
||||||
switch (IMode) {
|
switch (IMode) {
|
||||||
case ExprEngine::Inline_None:
|
case ExprEngine::Inline_Minimal:
|
||||||
llvm::errs() << " Inline_None";
|
llvm::errs() << " Inline_Minimal";
|
||||||
break;
|
break;
|
||||||
case ExprEngine::Inline_All:
|
case ExprEngine::Inline_Regular:
|
||||||
llvm::errs() << " Inline_All";
|
llvm::errs() << " Inline_Regular";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
llvm::errs() << ")";
|
llvm::errs() << ")";
|
||||||
|
|
@ -284,7 +284,8 @@ public:
|
||||||
virtual void HandleTranslationUnit(ASTContext &C);
|
virtual void HandleTranslationUnit(ASTContext &C);
|
||||||
|
|
||||||
/// \brief Determine which inlining mode should be used when this function is
|
/// \brief Determine which inlining mode should be used when this function is
|
||||||
/// analyzed. For example, determines if the callees should be inlined.
|
/// analyzed. This allows to redefine the default inlining policies when
|
||||||
|
/// analyzing a given function.
|
||||||
ExprEngine::InliningModes
|
ExprEngine::InliningModes
|
||||||
getInliningModeForFunction(const Decl *D, SetOfConstDecls Visited);
|
getInliningModeForFunction(const Decl *D, SetOfConstDecls Visited);
|
||||||
|
|
||||||
|
|
@ -299,7 +300,7 @@ public:
|
||||||
/// set of functions which should be considered analyzed after analyzing the
|
/// set of functions which should be considered analyzed after analyzing the
|
||||||
/// given root function.
|
/// given root function.
|
||||||
void HandleCode(Decl *D, AnalysisMode Mode,
|
void HandleCode(Decl *D, AnalysisMode Mode,
|
||||||
ExprEngine::InliningModes IMode = ExprEngine::Inline_None,
|
ExprEngine::InliningModes IMode = ExprEngine::Inline_Minimal,
|
||||||
SetOfConstDecls *VisitedCallees = 0);
|
SetOfConstDecls *VisitedCallees = 0);
|
||||||
|
|
||||||
void RunPathSensitiveChecks(Decl *D,
|
void RunPathSensitiveChecks(Decl *D,
|
||||||
|
|
@ -410,22 +411,18 @@ static bool shouldSkipFunction(const Decl *D,
|
||||||
ExprEngine::InliningModes
|
ExprEngine::InliningModes
|
||||||
AnalysisConsumer::getInliningModeForFunction(const Decl *D,
|
AnalysisConsumer::getInliningModeForFunction(const Decl *D,
|
||||||
SetOfConstDecls Visited) {
|
SetOfConstDecls Visited) {
|
||||||
ExprEngine::InliningModes HowToInline =
|
|
||||||
(Mgr->shouldInlineCall()) ? ExprEngine::Inline_All :
|
|
||||||
ExprEngine::Inline_None;
|
|
||||||
|
|
||||||
// We want to reanalyze all ObjC methods as top level to report Retain
|
// We want to reanalyze all ObjC methods as top level to report Retain
|
||||||
// Count naming convention errors more aggressively. But we can turn off
|
// Count naming convention errors more aggressively. But we should tune down
|
||||||
// inlining when reanalyzing an already inlined function.
|
// inlining when reanalyzing an already inlined function.
|
||||||
if (Visited.count(D)) {
|
if (Visited.count(D)) {
|
||||||
assert(isa<ObjCMethodDecl>(D) &&
|
assert(isa<ObjCMethodDecl>(D) &&
|
||||||
"We are only reanalyzing ObjCMethods.");
|
"We are only reanalyzing ObjCMethods.");
|
||||||
const ObjCMethodDecl *ObjCM = cast<ObjCMethodDecl>(D);
|
const ObjCMethodDecl *ObjCM = cast<ObjCMethodDecl>(D);
|
||||||
if (ObjCM->getMethodFamily() != OMF_init)
|
if (ObjCM->getMethodFamily() != OMF_init)
|
||||||
HowToInline = ExprEngine::Inline_None;
|
return ExprEngine::Inline_Minimal;
|
||||||
}
|
}
|
||||||
|
|
||||||
return HowToInline;
|
return ExprEngine::Inline_Regular;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {
|
void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {
|
||||||
|
|
@ -595,7 +592,7 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
|
||||||
checkerMgr->runCheckersOnASTBody(D, *Mgr, BR);
|
checkerMgr->runCheckersOnASTBody(D, *Mgr, BR);
|
||||||
if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
|
if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
|
||||||
RunPathSensitiveChecks(D, IMode, VisitedCallees);
|
RunPathSensitiveChecks(D, IMode, VisitedCallees);
|
||||||
if (IMode != ExprEngine::Inline_None)
|
if (IMode != ExprEngine::Inline_Minimal)
|
||||||
NumFunctionsAnalyzed++;
|
NumFunctionsAnalyzed++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -361,3 +361,30 @@ CFStringRef testCovariantReturnType() {
|
||||||
}
|
}
|
||||||
return Str;
|
return Str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that we reanalyze ObjC methods which have been inlined. When reanalyzing
|
||||||
|
// them, make sure we inline very small functions.
|
||||||
|
|
||||||
|
@interface MyClass : NSObject
|
||||||
|
- (id)test_return_retained_NS;
|
||||||
|
- (void)test_return_retained;
|
||||||
|
@end
|
||||||
|
|
||||||
|
id returnInputParam(id x) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
@implementation MyClass
|
||||||
|
- (id)test_return_retained_NS {
|
||||||
|
// This method does not follow naming conventions, so a warning will be
|
||||||
|
// reported when it is reanalyzed at top level.
|
||||||
|
return returnInputParam([[NSString alloc] init]); // expected-warning {{leak}}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)test_return_retained {
|
||||||
|
id x = test_return_retained_NS(); // expected-warning {{leak}}
|
||||||
|
[x retain];
|
||||||
|
[x release];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue