A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://clang.llvm.org/doxygen/CalledOnceCheck_8cpp_source.html below:

clang: lib/Analysis/CalledOnceCheck.cpp Source File

29#include "llvm/ADT/BitVector.h" 30#include "llvm/ADT/BitmaskEnum.h" 31#include "llvm/ADT/PointerIntPair.h" 32#include "llvm/ADT/STLExtras.h" 33#include "llvm/ADT/Sequence.h" 34#include "llvm/ADT/SmallVector.h" 35#include "llvm/ADT/StringRef.h" 36#include "llvm/Support/Casting.h" 37#include "llvm/Support/Compiler.h" 38#include "llvm/Support/ErrorHandling.h" 42using namespace clang

;

45static constexpr unsigned

EXPECTED_MAX_NUMBER_OF_PARAMS = 2;

48static constexpr unsigned

EXPECTED_NUMBER_OF_BASIC_BLOCKS = 8;

51constexpr

llvm::StringLiteral CONVENTIONAL_NAMES[] = {

52 "completionHandler"

,

"completion"

,

"withCompletionHandler"

,

53 "withCompletion"

,

"completionBlock"

,

"withCompletionBlock"

,

54 "replyTo"

,

"reply"

,

"withReplyTo"

};

55constexpr

llvm::StringLiteral CONVENTIONAL_SUFFIXES[] = {

56 "WithCompletionHandler"

,

"WithCompletion"

,

"WithCompletionBlock"

,

57 "WithReplyTo"

,

"WithReply"

};

58constexpr

llvm::StringLiteral CONVENTIONAL_CONDITIONS[] = {

59 "error"

,

"cancel"

,

"shouldCall"

,

"done"

,

"OK"

,

"success"

};

61struct

KnownCalledOnceParameter {

62

llvm::StringLiteral FunctionName;

65constexpr

KnownCalledOnceParameter KNOWN_CALLED_ONCE_PARAMETERS[] = {

66

{llvm::StringLiteral{

"dispatch_async"

}, 1},

67

{llvm::StringLiteral{

"dispatch_async_and_wait"

}, 1},

68

{llvm::StringLiteral{

"dispatch_after"

}, 2},

69

{llvm::StringLiteral{

"dispatch_sync"

}, 1},

70

{llvm::StringLiteral{

"dispatch_once"

}, 1},

71

{llvm::StringLiteral{

"dispatch_barrier_async"

}, 1},

72

{llvm::StringLiteral{

"dispatch_barrier_async_and_wait"

}, 1},

73

{llvm::StringLiteral{

"dispatch_barrier_sync"

}, 1}};

75class

ParameterStatus {

154

DefinitelyCalled = 0x3,

156

NON_ERROR_STATUS = DefinitelyCalled,

170 constexpr

ParameterStatus() =

default

;

171

ParameterStatus(Kind K) : StatusKind(K) {

172

assert(!seenAnyCalls(K) &&

"Can't initialize status without a call"

);

174

ParameterStatus(Kind K,

const Expr

*Call) : StatusKind(K),

Call

(

Call

) {

175

assert(seenAnyCalls(K) &&

"This kind is not supposed to have a call"

);

178 const Expr

&getCall()

const

{

179

assert(seenAnyCalls(

getKind

()) &&

"ParameterStatus doesn't have a call"

);

182 static bool

seenAnyCalls(Kind K) {

183 return

(K & DefinitelyCalled) == DefinitelyCalled && K != Reported;

185 bool

seenAnyCalls()

const

{

return

seenAnyCalls(

getKind

()); }

187 static bool

isErrorStatus(Kind K) {

return

K > NON_ERROR_STATUS; }

188 bool

isErrorStatus()

const

{

return

isErrorStatus(

getKind

()); }

192 void

join(

const

ParameterStatus &

Other

) {

202

StatusKind |=

Other

.getKind();

214 Kind

StatusKind = NotVisited;

221

State(

unsigned

Size, ParameterStatus::Kind K = ParameterStatus::NotVisited)

222

: ParamData(

Size

, K) {}

226

ParameterStatus &getStatusFor(

unsigned

Index) {

return

ParamData[Index]; }

227 const

ParameterStatus &getStatusFor(

unsigned

Index)

const

{

228 return

ParamData[Index];

233 bool

seenAnyCalls(

unsigned

Index)

const

{

234 return

getStatusFor(Index).seenAnyCalls();

239 const Expr

&getCallFor(

unsigned

Index)

const

{

240 return

getStatusFor(Index).getCall();

243

ParameterStatus::Kind getKindFor(

unsigned

Index)

const

{

244 return

getStatusFor(Index).getKind();

247 bool

isVisited()

const

{

248 return

llvm::all_of(ParamData, [](

const

ParameterStatus &S) {

249 return

S.getKind() != ParameterStatus::NotVisited;

254 void

join(

const

State &

Other

) {

255

assert(ParamData.size() ==

Other

.ParamData.size() &&

256 "Couldn't join statuses with different sizes"

);

257 for

(

auto

Pair : llvm::zip(ParamData,

Other

.ParamData)) {

258

std::get<0>(Pair).join(std::get<1>(Pair));

262 using

iterator = ParamSizedVector<ParameterStatus>::iterator;

263 using

const_iterator = ParamSizedVector<ParameterStatus>::const_iterator;

265

iterator begin() {

return

ParamData.begin(); }

266

iterator end() {

return

ParamData.end(); }

268

const_iterator begin()

const

{

return

ParamData.begin(); }

269

const_iterator end()

const

{

return

ParamData.end(); }

272 return

ParamData ==

Other

.ParamData;

276

ParamSizedVector<ParameterStatus> ParamData;

310 bool

ShouldRetrieveFromComparisons =

false

) {

311 return

DeclRefFinder(ShouldRetrieveFromComparisons).Visit(

E

);

320 if

(!ShouldRetrieveFromComparisons)

334 if

(!ShouldRetrieveFromComparisons)

353 if

(!ShouldRetrieveFromComparisons)

359 case

Builtin::BI__builtin_expect:

360 case

Builtin::BI__builtin_expect_with_probability: {

364 return

Candidate !=

nullptr

? Candidate :

Visit

(CE->

getArg

(1));

367 case

Builtin::BI__builtin_unpredictable:

382 return E

!= DeclutteredExpr ?

Visit

(DeclutteredExpr) : nullptr;

386

DeclRefFinder(

bool

ShouldRetrieveFromComparisons)

387

: ShouldRetrieveFromComparisons(ShouldRetrieveFromComparisons) {}

389 bool

ShouldRetrieveFromComparisons;

393 bool

ShouldRetrieveFromComparisons =

false

) {

394 return

DeclRefFinder::find(In, ShouldRetrieveFromComparisons);

398

findReferencedParmVarDecl(

const Expr

*In,

399 bool

ShouldRetrieveFromComparisons =

false

) {

401

findDeclRefExpr(In, ShouldRetrieveFromComparisons)) {

402 return

dyn_cast<ParmVarDecl>(DR->getDecl());

409const Expr

*getCondition(

const Stmt

*S) {

414 if

(

const auto

*

If

= dyn_cast<IfStmt>(S)) {

415 return If

->getCond();

417 if

(

const auto

*Ternary = dyn_cast<AbstractConditionalOperator>(S)) {

418 return

Ternary->getCond();

431 static constexpr unsigned

EXPECTED_NUMBER_OF_NAMES = 5;

432 using

NameCollection =

435 static

NameCollection collect(

const Expr

*From) {

437

Impl.TraverseStmt(

const_cast<Expr

*

>

(From));

442

Result.push_back(

E

->getDecl()->getName());

447

llvm::StringRef Name;

449 if

(

E

->isImplicitProperty()) {

451 if

(

E

->isMessagingGetter()) {

452

PropertyMethodDecl =

E

->getImplicitPropertyGetter();

454

PropertyMethodDecl =

E

->getImplicitPropertySetter();

456

assert(PropertyMethodDecl &&

457 "Implicit property must have associated declaration"

);

460

assert(

E

->isExplicitProperty());

461

Name =

E

->getExplicitProperty()->getName();

464

Result.push_back(Name);

469

NamesCollector() =

default

;

470

NameCollection Result;

474bool

mentionsAnyOfConventionalNames(

const Expr

*

E

) {

477 return

llvm::any_of(MentionedNames, [](llvm::StringRef ConditionName) {

479

CONVENTIONAL_CONDITIONS,

480

[ConditionName](

const

llvm::StringLiteral &Conventional) {

481 return

ConditionName.contains_insensitive(Conventional);

488struct

Clarification {

490 const Stmt

*Location;

495class

NotCalledClarifier

497

std::optional<Clarification>> {

511 static

std::optional<Clarification> clarify(

const CFGBlock

*Conditional,

514 return

NotCalledClarifier{

Conditional

, SuccWithoutCall}.Visit(Terminator);

519

std::optional<Clarification> VisitIfStmt(

const IfStmt

*

If

) {

520 return

VisitBranchingBlock(

If

, NeverCalledReason::IfThen);

523

std::optional<Clarification>

525 return

VisitBranchingBlock(Ternary, NeverCalledReason::IfThen);

529 const Stmt

*CaseToBlame = SuccInQuestion->getLabel();

537

Case = Case->getNextSwitchCase()) {

538 if

(Case == CaseToBlame) {

543

llvm_unreachable(

"Found unexpected switch structure"

);

546

std::optional<Clarification> VisitForStmt(

const ForStmt

*For) {

547 return

VisitBranchingBlock(For, NeverCalledReason::LoopEntered);

550

std::optional<Clarification> VisitWhileStmt(

const WhileStmt

*While) {

551 return

VisitBranchingBlock(While, NeverCalledReason::LoopEntered);

554

std::optional<Clarification>

556

assert(

Parent

->succ_size() == 2 &&

557 "Branching block should have exactly two successors"

);

558 unsigned

SuccessorIndex = getSuccessorIndex(Parent, SuccInQuestion);

560

updateForSuccessor(DefaultReason, SuccessorIndex);

561 return

Clarification{ActualReason, Terminator};

564

std::optional<Clarification> VisitBinaryOperator(

const BinaryOperator

*) {

569

std::optional<Clarification> VisitStmt(

const Stmt

*Terminator) {

578 static unsigned

getSuccessorIndex(

const CFGBlock

*Parent,

581

assert(It !=

Parent

->succ_end() &&

582 "Given blocks should be in parent-child relationship"

);

583 return

It -

Parent

->succ_begin();

588 unsigned

SuccessorIndex) {

589

assert(SuccessorIndex <= 1);

591 static_cast<unsigned>

(ReasonForTrueBranch) + SuccessorIndex;

593 static_cast<unsigned>

(NeverCalledReason::LARGEST_VALUE));

607 bool

CheckConventionalParameters) {

608

CalledOnceChecker(AC, Handler, CheckConventionalParameters).check();

613 bool

CheckConventionalParameters)

614

: FunctionCFG(*AC.getCFG()), AC(AC), Handler(Handler),

615

CheckConventionalParameters(CheckConventionalParameters),

617

initDataStructures();

618

assert((size() == 0 || !States.empty()) &&

619 "Data structures are inconsistent"

);

626 void

initDataStructures() {

627 const Decl

*AnalyzedDecl = AC.getDecl();

629 if

(

const auto

*Function = dyn_cast<FunctionDecl>(AnalyzedDecl)) {

630

findParamsToTrack(Function);

631

}

else if

(

const auto

*Method = dyn_cast<ObjCMethodDecl>(AnalyzedDecl)) {

632

findParamsToTrack(Method);

633

}

else if

(

const auto

*

Block

= dyn_cast<BlockDecl>(AnalyzedDecl)) {

634

findCapturesToTrack(

Block

);

635

findParamsToTrack(

Block

);

641

CFGSizedVector<State>(FunctionCFG.getNumBlockIDs(), State(size()));

650 if

(shouldBeCalledOnce(ParamContext,

P

)) {

651

TrackedParams.push_back(

P

);

657 template

<

class

FunctionLikeDecl>

658 void

findParamsToTrack(

const

FunctionLikeDecl *Function) {

659 for

(

unsigned

Index : llvm::seq<unsigned>(0u,

Function

->param_size())) {

660 if

(shouldBeCalledOnce(Function, Index)) {

661

TrackedParams.push_back(

Function

->getParamDecl(Index));

672 if

(size() == 0 || isPossiblyEmptyImpl())

676

llvm::none_of(States, [](

const

State &S) {

return

S.isVisited(); }) &&

677 "None of the blocks should be 'visited' before the analysis"

);

716 const CFGBlock

*Exit = &FunctionCFG.getExit();

717

assignState(Exit, State(size(), ParameterStatus::NotCalled));

718

Worklist.enqueuePredecessors(Exit);

720 while

(

const CFGBlock

*BB = Worklist.dequeue()) {

721

assert(BB &&

"Worklist should filter out null blocks"

);

723

assert(CurrentState.isVisited() &&

724 "After the check, basic block should be visited"

);

728 if

(assignState(BB, CurrentState)) {

729

Worklist.enqueuePredecessors(BB);

736

checkEntry(&FunctionCFG.getEntry());

741

CurrentState = joinSuccessors(BB);

742

assert(CurrentState.isVisited() &&

743 "Shouldn't start with a 'not visited' state"

);

755 for

(

const CFGElement

&Element : llvm::reverse(*BB)) {

756 if

(std::optional<CFGStmt> S = Element.

getAs

<

CFGStmt

>()) {

761 void

check(

const Stmt

*S) {

Visit

(S); }

763 void

checkEntry(

const CFGBlock

*Entry) {

769 const

State &EntryStatus = getState(Entry);

770

llvm::BitVector NotCalledOnEveryPath(size(),

false

);

771

llvm::BitVector NotUsedOnEveryPath(size(),

false

);

774 for

(

const auto

&IndexedStatus : llvm::enumerate(EntryStatus)) {

777 switch

(IndexedStatus.value().getKind()) {

778 case

ParameterStatus::NotCalled:

782 if

(!hasEverEscaped(IndexedStatus.index())) {

796

NotUsedOnEveryPath[IndexedStatus.index()] =

true

;

800 case

ParameterStatus::MaybeCalled:

808

NotCalledOnEveryPath[IndexedStatus.index()] =

true

;

816 if

(NotCalledOnEveryPath.none() && NotUsedOnEveryPath.none() &&

820

!FunctionHasCleanupVars)

841 for

(

const CFGBlock

*BB : FunctionCFG) {

845 const

State &BlockState = getState(BB);

847 for

(

unsigned

Index : llvm::seq(0u, size())) {

857 if

(NotCalledOnEveryPath[Index] &&

858

BlockState.getKindFor(Index) == ParameterStatus::MaybeCalled) {

860

findAndReportNotCalledBranches(BB, Index);

861

}

else if

(NotUsedOnEveryPath[Index] &&

862

isLosingEscape(BlockState, BB, Index)) {

864

findAndReportNotCalledBranches(BB, Index,

true

);

872 if

(

auto

Index = getIndexOfCallee(

Call

)) {

873

processCallFor(*Index,

Call

);

880 template

<

class

CallLikeExpr>

881 void

checkIndirectCall(

const

CallLikeExpr *CallOrMessage) {

884 llvm::ArrayRef

(CallOrMessage->getArgs(), CallOrMessage->getNumArgs());

887 for

(

const auto

&Argument : llvm::enumerate(Arguments)) {

888 if

(

auto

Index = getIndexOfExpression(Argument.value())) {

889 if

(shouldBeCalledOnce(CallOrMessage, Argument.index())) {

892

processCallFor(*Index, CallOrMessage);

896

processEscapeFor(*Index);

904 void

processCallFor(

unsigned

Index,

const Expr

*

Call

) {

905

ParameterStatus &CurrentParamStatus = CurrentState.getStatusFor(Index);

907 if

(CurrentParamStatus.seenAnyCalls()) {

916

CurrentParamStatus.getKind() == ParameterStatus::DefinitelyCalled);

920

CurrentParamStatus = ParameterStatus::Reported;

922

}

else if

(CurrentParamStatus.getKind() != ParameterStatus::Reported) {

925

ParameterStatus Called(ParameterStatus::DefinitelyCalled,

Call

);

926

CurrentParamStatus = Called;

931 void

processEscapeFor(

unsigned

Index) {

932

ParameterStatus &CurrentParamStatus = CurrentState.getStatusFor(Index);

935 if

(CurrentParamStatus.isErrorStatus() &&

936

CurrentParamStatus.getKind() != ParameterStatus::Kind::Reported) {

937

CurrentParamStatus = ParameterStatus::Escaped;

941 void

findAndReportNotCalledBranches(

const CFGBlock

*

Parent

,

unsigned

Index,

942 bool

IsEscape =

false

) {

947 if

(getState(Succ).getKindFor(Index) == ParameterStatus::NotCalled) {

948

assert(

Parent

->succ_size() >= 2 &&

949 "Block should have at least two successors at this point"

);

950 if

(

auto

Clarification = NotCalledClarifier::clarify(

Parent

, Succ)) {

953 Parameter

, AC.getDecl(), Clarification->Location,

954

Clarification->Reason, !IsEscape, !isExplicitlyMarked(

Parameter

));

966 return Parameter

->hasAttr<CalledOnceAttr>();

970 static bool

isConventional(llvm::StringRef Name) {

971 return

llvm::count(CONVENTIONAL_NAMES, Name) != 0;

975 static bool

hasConventionalSuffix(llvm::StringRef Name) {

976 return

llvm::any_of(CONVENTIONAL_SUFFIXES, [Name](llvm::StringRef Suffix) {

977 return

Name.ends_with(Suffix);

982 static bool

isConventional(

QualType

Ty) {

993 static bool

isOnlyParameterConventional(

const FunctionDecl

*Function) {

995 return Function

->getNumParams() == 1 && II &&

996

hasConventionalSuffix(II->

getName

());

1003 static

std::optional<bool> isConventionalSwiftAsync(

const Decl

*

D

,

1004 unsigned

ParamIndex) {

1005 if

(

const

SwiftAsyncAttr *A =

D

->

getAttr

<SwiftAsyncAttr>()) {

1006 if

(A->getKind() == SwiftAsyncAttr::None) {

1010 return

A->getCompletionHandlerIndex().getASTIndex() == ParamIndex;

1012 return

std::nullopt;

1016 static bool

isInitMethod(

Selector

MethodSelector) {

1021 static bool

isConventionalSelectorPiece(

Selector

MethodSelector,

1022 unsigned

PieceIndex,

1024 if

(!isConventional(PieceType) || isInitMethod(MethodSelector)) {

1029

assert(PieceIndex == 0);

1030 return

hasConventionalSuffix(MethodSelector.

getNameForSlot

(0));

1033

llvm::StringRef PieceName = MethodSelector.

getNameForSlot

(PieceIndex);

1034 return

isConventional(PieceName) || hasConventionalSuffix(PieceName);

1038 return

isExplicitlyMarked(

Parameter

) ||

1039

(CheckConventionalParameters &&

1040

(isConventional(

Parameter

->getName()) ||

1041

hasConventionalSuffix(

Parameter

->getName())) &&

1042

isConventional(

Parameter

->getType()));

1045 bool

shouldBeCalledOnce(

const DeclContext

*ParamContext,

1048 if

(

const auto

*Function = dyn_cast<FunctionDecl>(ParamContext)) {

1049 return

shouldBeCalledOnce(Function, ParamIndex);

1051 if

(

const auto

*Method = dyn_cast<ObjCMethodDecl>(ParamContext)) {

1052 return

shouldBeCalledOnce(Method, ParamIndex);

1054 return

shouldBeCalledOnce(Param);

1057 bool

shouldBeCalledOnce(

const BlockDecl

*

Block

,

unsigned

ParamIndex)

const

{

1058 return

shouldBeCalledOnce(

Block

->getParamDecl(ParamIndex));

1062 unsigned

ParamIndex)

const

{

1063 if

(ParamIndex >=

Function

->getNumParams()) {

1067 if

(

auto

ConventionalAsync =

1068

isConventionalSwiftAsync(Function, ParamIndex)) {

1069 return

*ConventionalAsync;

1072 return

shouldBeCalledOnce(

Function

->getParamDecl(ParamIndex)) ||

1073

(CheckConventionalParameters &&

1074

isOnlyParameterConventional(Function));

1078 unsigned

ParamIndex)

const

{

1080 if

(ParamIndex >= MethodSelector.

getNumArgs

()) {

1085 if

(

auto

ConventionalAsync = isConventionalSwiftAsync(Method, ParamIndex)) {

1086 return

*ConventionalAsync;

1090 return

shouldBeCalledOnce(

Parameter

) ||

1091

(CheckConventionalParameters &&

1092

isConventionalSelectorPiece(MethodSelector, ParamIndex,

1096 bool

shouldBeCalledOnce(

const CallExpr

*

Call

,

unsigned

ParamIndex)

const

{

1098 return Function

&& shouldBeCalledOnce(Function, ParamIndex);

1102 unsigned

ParamIndex)

const

{

1104 return

Method && ParamIndex < Method->

param_size

() &&

1105

shouldBeCalledOnce(Method, ParamIndex);

1113 if

(

const BlockDecl

*

Block

= dyn_cast<BlockDecl>(AC.getDecl())) {

1131

Current !=

nullptr

; Prev = Current, Current = PM.

getParent

(Current)) {

1133 if

(isa<CastExpr>(Current) || isa<ParenExpr>(Current))

1138 if

(

const auto

*

Call

= dyn_cast<CallExpr>(Current)) {

1140 if

(

Call

->getCallee() == Prev)

1144 return

shouldBlockArgumentBeCalledOnce(

Call

, Prev) ?

Call

:

nullptr

;

1146 if

(

const auto

*Message = dyn_cast<ObjCMessageExpr>(Current)) {

1147 return

shouldBlockArgumentBeCalledOnce(Message, Prev) ? Message

1157 template

<

class

CallLikeExpr>

1158 bool

shouldBlockArgumentBeCalledOnce(

const

CallLikeExpr *CallOrMessage,

1159 const Stmt

*BlockArgument)

const

{

1162 llvm::ArrayRef

(CallOrMessage->getArgs(), CallOrMessage->getNumArgs());

1164 for

(

const auto

&Argument : llvm::enumerate(Arguments)) {

1165 if

(Argument.value() == BlockArgument) {

1166 return

shouldBlockArgumentBeCalledOnce(CallOrMessage, Argument.index());

1173 bool

shouldBlockArgumentBeCalledOnce(

const CallExpr

*

Call

,

1174 unsigned

ParamIndex)

const

{

1176 return

shouldBlockArgumentBeCalledOnce(Function, ParamIndex) ||

1177

shouldBeCalledOnce(

Call

, ParamIndex);

1181 unsigned

ParamIndex)

const

{

1184 return

shouldBeCalledOnce(Message, ParamIndex);

1187 static bool

shouldBlockArgumentBeCalledOnce(

const FunctionDecl

*Function,

1188 unsigned

ParamIndex) {

1195

llvm::any_of(KNOWN_CALLED_ONCE_PARAMETERS,

1196

[Function, ParamIndex](

1197 const

KnownCalledOnceParameter &

Reference

) {

1214 bool

isPossiblyEmptyImpl()

const

{

1215 if

(!isa<ObjCMethodDecl>(AC.getDecl())) {

1222 if

(FunctionCFG.size() == 2) {

1229 if

(FunctionCFG.size() == 3) {

1230 const CFGBlock

&Entry = FunctionCFG.getEntry();

1253 return

llvm::all_of(FunctionCFG, [](

const CFGBlock

*BB) {

1263

std::unique_ptr<ParentMap> ReturnChildren;

1265 return

llvm::all_of(

1268

[&ReturnChildren](

const CFGElement

&Element) {

1269 if

(std::optional<CFGStmt> S = Element.

getAs

<

CFGStmt

>()) {

1270

const Stmt *SuspiciousStmt = S->getStmt();

1272

if (isa<ReturnStmt>(SuspiciousStmt)) {

1275

ReturnChildren = std::make_unique<ParentMap>(

1276

const_cast<Stmt *>(SuspiciousStmt));

1281 return

SuspiciousStmt->getBeginLoc().isMacroID() ||

1283

ReturnChildren->hasParent(SuspiciousStmt));

1291 bool

hasEverEscaped(

unsigned

Index)

const

{

1292 return

llvm::any_of(States, [Index](

const

State &StateForOneBB) {

1293 return

StateForOneBB.getKindFor(Index) == ParameterStatus::Escaped;

1299

State &getState(

const CFGBlock

*BB) {

1303 const

State &getState(

const CFGBlock

*BB)

const

{

1312 bool

assignState(

const CFGBlock

*BB,

const

State &ToAssign) {

1313

State &Current = getState(BB);

1314 if

(Current == ToAssign) {

1323

State joinSuccessors(

const CFGBlock

*BB)

const

{

1325

llvm::make_filter_range(BB->

succs

(), [

this

](

const CFGBlock

*Succ) {

1326

return Succ && this->getState(Succ).isVisited();

1329

assert(!Succs.empty() &&

1330 "Basic block should have at least one visited successor"

);

1332

State Result = getState(*Succs.begin());

1334 for

(

const CFGBlock

*Succ : llvm::drop_begin(Succs, 1)) {

1335

Result.join(getState(Succ));

1339

handleConditional(BB,

Condition

, Result);

1346

State &ToAlter)

const

{

1347

handleParameterCheck(BB,

Condition

, ToAlter);

1348 if

(SuppressOnConventionalErrorPaths) {

1349

handleConventionalCheck(BB,

Condition

, ToAlter);

1354

State &ToAlter)

const

{

1369

ParameterStatus &CurrentStatus = ToAlter.getStatusFor(*Index);

1381 const

ParameterStatus &StatusInSucc =

1382

getState(Succ).getStatusFor(*Index);

1384 if

(StatusInSucc.isErrorStatus()) {

1389

CurrentStatus = StatusInSucc;

1391 if

(StatusInSucc.getKind() == ParameterStatus::DefinitelyCalled) {

1404

State &ToAlter)

const

{

1408 if

(!mentionsAnyOfConventionalNames(

Condition

)) {

1412 for

(

const auto

&IndexedStatus : llvm::enumerate(ToAlter)) {

1419

ParameterStatus &CurrentStatus = IndexedStatus.value();

1428 if

(isLosingCall(ToAlter, BB, IndexedStatus.index()) ||

1429

isLosingEscape(ToAlter, BB, IndexedStatus.index())) {

1430

CurrentStatus = ParameterStatus::Escaped;

1435 bool

isLosingCall(

const

State &StateAfterJoin,

const CFGBlock

*JoinBlock,

1436 unsigned

ParameterIndex)

const

{

1439 return

isLosingJoin(StateAfterJoin, JoinBlock, ParameterIndex,

1440

ParameterStatus::MaybeCalled,

1441

ParameterStatus::DefinitelyCalled);

1444 bool

isLosingEscape(

const

State &StateAfterJoin,

const CFGBlock

*JoinBlock,

1445 unsigned

ParameterIndex)

const

{

1447 return

isLosingJoin(StateAfterJoin, JoinBlock, ParameterIndex,

1448

ParameterStatus::NotCalled, ParameterStatus::Escaped);

1451 bool

isLosingJoin(

const

State &StateAfterJoin,

const CFGBlock

*JoinBlock,

1452 unsigned

ParameterIndex, ParameterStatus::Kind AfterJoin,

1453

ParameterStatus::Kind BeforeJoin)

const

{

1454

assert(!ParameterStatus::isErrorStatus(BeforeJoin) &&

1455

ParameterStatus::isErrorStatus(AfterJoin) &&

1456 "It's not a losing join if statuses do not represent " 1457 "correct-to-error transition"

);

1459 const

ParameterStatus &CurrentStatus =

1460

StateAfterJoin.getStatusFor(ParameterIndex);

1462 return

CurrentStatus.getKind() == AfterJoin &&

1463

anySuccessorHasStatus(JoinBlock, ParameterIndex, BeforeJoin);

1468 bool

anySuccessorHasStatus(

const CFGBlock

*

Parent

,

unsigned

ParameterIndex,

1469

ParameterStatus::Kind ToFind)

const

{

1470 return

llvm::any_of(

1471 Parent

->succs(), [

this

, ParameterIndex, ToFind](

const CFGBlock

*Succ) {

1472

return Succ && getState(Succ).getKindFor(ParameterIndex) == ToFind;

1477 void

checkEscapee(

const Expr

*

E

) {

1486

processEscapeFor(*Index);

1491 void

markNoReturn() {

1492 for

(ParameterStatus &PS : CurrentState) {

1493

PS = ParameterStatus::NoReturn;

1502 if

(

auto

Index = getIndexOfExpression(

Assignment

->getLHS())) {

1506 if

(

auto

Constant =

1507 Assignment

->getRHS()->IgnoreParenCasts()->getIntegerConstantExpr(

1508

AC.getASTContext())) {

1510

ParameterStatus &CurrentParamStatus = CurrentState.getStatusFor(*Index);

1512 if

(0 == *Constant && CurrentParamStatus.seenAnyCalls()) {

1521

CurrentParamStatus = ParameterStatus::Reported;

1534

checkDirectCall(

Call

);

1536

checkIndirectCall(

Call

);

1542 if

(

const Expr

*Receiver = Message->getInstanceReceiver()) {

1543

checkEscapee(Receiver);

1546

checkIndirectCall(Message);

1563 const Expr

*CalledOnceCallSite = getBlockGuaraneedCallSite(

Block

);

1568 if

(CalledOnceCallSite) {

1574 for

(

const auto

&

Capture

:

Block

->getBlockDecl()->captures()) {

1576 if

(

auto

Index =

getIndex

(*Param)) {

1577 if

(CalledOnceCallSite) {

1580

processCallFor(*Index, CalledOnceCallSite);

1585

processEscapeFor(*Index);

1593 if

(Op->

getOpcode

() == clang::BO_Assign) {

1597

checkEscapee(Op->

getRHS

());

1600

checkSuppression(Op);

1604 void

VisitDeclStmt(

const DeclStmt

*DS) {

1610 if

(

const auto

*Var = dyn_cast<VarDecl>(

Declaration

)) {

1611 if

(Var->getInit()) {

1612

checkEscapee(Var->getInit());

1615 if

(Var->hasAttr<CleanupAttr>()) {

1616

FunctionHasCleanupVars =

true

;

1626 if

(

Cast

->getType().getCanonicalType()->isVoidType()) {

1627

checkEscapee(

Cast

->getSubExpr());

1637 unsigned

size()

const

{

return

TrackedParams.size(); }

1639

std::optional<unsigned> getIndexOfCallee(

const CallExpr

*

Call

)

const

{

1640 return

getIndexOfExpression(

Call

->getCallee());

1643

std::optional<unsigned> getIndexOfExpression(

const Expr

*

E

)

const

{

1648 return

std::nullopt;

1659

ParamSizedVector<const ParmVarDecl *>::const_iterator It =

1660

llvm::find(TrackedParams, &

Parameter

);

1662 if

(It != TrackedParams.end()) {

1663 return

It - TrackedParams.begin();

1666 return

std::nullopt;

1669 const ParmVarDecl

*getParameter(

unsigned

Index)

const

{

1670

assert(Index < TrackedParams.size());

1671 return

TrackedParams[Index];

1674 const CFG

&FunctionCFG;

1677 bool

CheckConventionalParameters;

1684 bool

SuppressOnConventionalErrorPaths =

false

;

1691 bool

FunctionHasCleanupVars =

false

;

1694

ParamSizedVector<const ParmVarDecl *> TrackedParams;

1695

CFGSizedVector<State> States;

1703 bool

CheckConventionalParameters) {

1704

CalledOnceChecker::check(AC, Handler, CheckConventionalParameters);

Defines the clang::ASTContext interface.

This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...

Defines enum values for all the target-independent builtin functions.

static std::optional< NonLoc > getIndex(ProgramStateRef State, const ElementRegion *ER, CharKind CK)

@ LLVM_MARK_AS_BITMASK_ENUM

static Decl::Kind getKind(const Decl *D)

Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.

Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.

Defines the Objective-C statement AST node classes.

static QualType getPointeeType(const MemRegion *R)

C Language Family Type Representation.

AbstractConditionalOperator - An abstract base class for ConditionalOperator and BinaryConditionalOpe...

AnalysisDeclContext contains the context data for the function, method or block under analysis.

A builtin binary operation expression such as "x + y" or "x <= y".

Represents a block literal declaration, which is like an unnamed FunctionDecl.

BlockExpr - Adaptor class for mixing a BlockDecl with expressions.

Represents a single basic block in a source-level CFG.

bool hasNoReturnElement() const

succ_iterator succ_begin()

Stmt * getTerminatorStmt()

unsigned getBlockID() const

AdjacentBlocks::const_iterator const_succ_iterator

Represents a top-level expression in a basic block.

std::optional< T > getAs() const

Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...

Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.

CStyleCastExpr - An explicit cast in C (C99 6.5.4) or a C-style cast in C++ (C++ [expr....

CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).

Expr * getArg(unsigned Arg)

getArg - Return the specified argument.

unsigned getBuiltinCallee() const

getBuiltinCallee - If this is a call to a builtin, return the builtin ID of the callee.

unsigned getNumArgs() const

getNumArgs - Return the number of actual arguments to this call.

virtual void handleBlockThatIsGuaranteedToBeCalledOnce(const BlockDecl *Block)

Called when the block is guaranteed to be called exactly once.

virtual void handleBlockWithNoGuarantees(const BlockDecl *Block)

Called when the block has no guarantees about how many times it can get called.

virtual void handleDoubleCall(const ParmVarDecl *Parameter, const Expr *Call, const Expr *PrevCall, bool IsCompletionHandler, bool Poised)

Called when parameter is called twice.

virtual void handleNeverCalled(const ParmVarDecl *Parameter, bool IsCompletionHandler)

Called when parameter is not called at all.

virtual void handleCapturedNeverCalled(const ParmVarDecl *Parameter, const Decl *Where, bool IsCompletionHandler)

Called when captured parameter is not called at all.

ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.

DeclContext - This is used only as base class of specific decl types that can act as declaration cont...

A reference to a declared variable, function, enum, etc.

DeclStmt - Adaptor class for mixing declarations with statements and expressions.

const DeclGroupRef getDeclGroup() const

Decl - This represents one declaration (or definition), e.g.

Recursive AST visitor that supports extension via dynamic dispatch.

This represents one expression.

Expr * IgnoreParenCasts() LLVM_READONLY

Skip past any parentheses and casts which might surround this expression until reaching a fixed point...

ForStmt - This represents a 'for (init;cond;inc)' stmt.

Represents a function declaration or definition.

FunctionType - C99 6.7.5.3 - Function Declarators.

One of these records is kept for each identifier that is lexed.

StringRef getName() const

Return the actual identifier string.

IfStmt - This represents an if/then/else.

Represents Objective-C's @throw statement.

An expression that sends a message to the given Objective-C object or class.

ObjCMethodDecl - Represents an instance or class method declaration.

unsigned param_size() const

Selector getSelector() const

ParmVarDecl * getParamDecl(unsigned Idx)

ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC property.

OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class.

Expr * getSourceExpr() const

The source expression of an opaque value expression is the expression which originally generated the ...

Stmt * getParent(Stmt *) const

Represents a parameter to a function.

unsigned getFunctionScopeIndex() const

Returns the index of this parameter in its prototype or method scope.

A (possibly-)qualified type.

Smart pointer class that efficiently represents Objective-C method names.

StringRef getNameForSlot(unsigned argIndex) const

Retrieve the name at a given position in the selector.

ObjCMethodFamily getMethodFamily() const

Derive the conventional family of this method.

unsigned getNumArgs() const

RetTy Visit(PTR(Stmt) S, ParamTys... P)

Stmt - This represents one statement.

SwitchStmt - This represents a 'switch' stmt.

bool isBlockPointerType() const

const T * castAs() const

Member-template castAs<specific type>.

UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...

Expr * getSubExpr() const

WhileStmt - This represents a 'while' stmt.

ValueDecl * getVariable() const

bool Call(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)

bool Cast(InterpState &S, CodePtr OpPC)

The JSON file list parser is used to communicate input to InstallAPI.

@ If

'if' clause, allowed on all the Compute Constructs, Data Constructs, Executable Constructs,...

bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)

@ Parameter

The parameter type of a method or function.

void checkCalledOnceParameters(AnalysisDeclContext &AC, CalledOnceCheckHandler &Handler, bool CheckConventionalParameters)

Check given CFG for 'called once' parameter violations.

@ Other

Other implicit parameter.

A worklist implementation for backward dataflow analysis.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4