diff options
author | DeLesley Hutchins <delesley@google.com> | 2013-10-17 22:53:04 +0000 |
---|---|---|
committer | DeLesley Hutchins <delesley@google.com> | 2013-10-17 22:53:04 +0000 |
commit | 36ea1dd4fc5e193d0eb7f6bf69f15d3779b6da24 (patch) | |
tree | 1995fb9ee35a51717ef613dfd7b3280928716ebc /clang/lib | |
parent | c1d547129185cabebc2d0857eea6a03d5bdf8b81 (diff) | |
download | bcm5719-llvm-36ea1dd4fc5e193d0eb7f6bf69f15d3779b6da24.tar.gz bcm5719-llvm-36ea1dd4fc5e193d0eb7f6bf69f15d3779b6da24.zip |
Consumed Analysis: Allow parameters that are passed by non-const reference
to be treated as return values, and marked with the "returned_typestate"
attribute. Patch by chris.wailes@gmail.com; reviewed by delesley@google.com.
llvm-svn: 192932
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Analysis/Consumed.cpp | 46 | ||||
-rw-r--r-- | clang/lib/Sema/AnalysisBasedWarnings.cpp | 12 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 20 |
3 files changed, 68 insertions, 10 deletions
diff --git a/clang/lib/Analysis/Consumed.cpp b/clang/lib/Analysis/Consumed.cpp index b06fb155d5b..021c26dff2f 100644 --- a/clang/lib/Analysis/Consumed.cpp +++ b/clang/lib/Analysis/Consumed.cpp @@ -87,7 +87,7 @@ static SourceLocation getLastStmtLoc(const CFGBlock *Block) { Loc = getFirstStmtLoc(*Block->succ_begin()); if (Loc.isValid()) return Loc; - + // If we have one predecessor, return the last statement in that block if (Block->pred_size() == 1 && *Block->pred_begin()) return getLastStmtLoc(*Block->pred_begin()); @@ -572,7 +572,8 @@ void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) { unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams(); for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) { - QualType ParamType = FunDecl->getParamDecl(Index - Offset)->getType(); + const ParmVarDecl *Param = FunDecl->getParamDecl(Index - Offset); + QualType ParamType = Param->getType(); InfoEntry Entry = PropagationMap.find(Call->getArg(Index)); @@ -588,6 +589,10 @@ void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) { StateMap->setState(PInfo.getVar(), consumed::CS_Consumed); + } else if (Param->hasAttr<ReturnTypestateAttr>()) { + StateMap->setState(PInfo.getVar(), + mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>())); + } else if (!(ParamType.isConstQualified() || ((ParamType->isReferenceType() || ParamType->isPointerType()) && @@ -820,7 +825,9 @@ void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) { } void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) { - if (ConsumedState ExpectedState = Analyzer.getExpectedReturnState()) { + ConsumedState ExpectedState = Analyzer.getExpectedReturnState(); + + if (ExpectedState != CS_None) { InfoEntry Entry = PropagationMap.find(Ret->getRetValue()); if (Entry != PropagationMap.end()) { @@ -835,6 +842,9 @@ void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) { stateToString(RetState)); } } + + StateMap->checkParamsForReturnTypestate(Ret->getLocStart(), + Analyzer.WarningsHandler); } void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) { @@ -1054,6 +1064,31 @@ bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) { return false; } +void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc, + ConsumedWarningsHandlerBase &WarningsHandler) const { + + ConsumedState ExpectedState; + + for (MapType::const_iterator DMI = Map.begin(), DME = Map.end(); DMI != DME; + ++DMI) { + + if (isa<ParmVarDecl>(DMI->first)) { + const ParmVarDecl *Param = cast<ParmVarDecl>(DMI->first); + + if (!Param->hasAttr<ReturnTypestateAttr>()) continue; + + ExpectedState = + mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>()); + + if (DMI->second != ExpectedState) { + WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc, + Param->getNameAsString(), stateToString(ExpectedState), + stateToString(DMI->second)); + } + } + } +} + ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const { MapType::const_iterator Entry = Map.find(Var); @@ -1375,6 +1410,11 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) { CurrStates = NULL; } } + + if (CurrBlock == &AC.getCFG()->getExit() && + D->getCallResultType()->isVoidType()) + CurrStates->checkParamsForReturnTypestate(D->getLocation(), + WarningsHandler); } // End of block iterator. // Delete the last existing state map. diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 737f59a3f97..2d65980ec07 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -1484,6 +1484,18 @@ public: Warnings.push_back(DelayedDiag(Warning, OptionalNotes())); } + void warnParamReturnTypestateMismatch(SourceLocation Loc, + StringRef VariableName, + StringRef ExpectedState, + StringRef ObservedState) { + + PartialDiagnosticAt Warning(Loc, S.PDiag( + diag::warn_param_return_typestate_mismatch) << VariableName << + ExpectedState << ObservedState); + + Warnings.push_back(DelayedDiag(Warning, OptionalNotes())); + } + void warnReturnTypestateForUnconsumableType(SourceLocation Loc, StringRef TypeName) { PartialDiagnosticAt Warning(Loc, S.PDiag( diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index c08767574ce..c3e6bc4cc34 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -1068,6 +1068,14 @@ static void handleCallableWhenAttr(Sema &S, Decl *D, static void handleReturnTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (!checkAttributeNumArgs(S, Attr, 1)) return; + + if (!(isa<FunctionDecl>(D) || isa<ParmVarDecl>(D))) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << + Attr.getName() << ExpectedFunctionMethodOrParameter; + return; + } + ReturnTypestateAttr::ConsumedState ReturnState; if (Attr.isArgIdent(0)) { @@ -1084,18 +1092,16 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D, return; } - if (!isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << - Attr.getName() << ExpectedFunction; - return; - } - // FIXME: This check is currently being done in the analysis. It can be // enabled here only after the parser propagates attributes at // template specialization definition, not declaration. //QualType ReturnType; // - //if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { + //if (const ParmVarDecl *Param = dyn_cast<ParmVarDecl>(D)) { + // ReturnType = Param->getType(); + // + //} else if (const CXXConstructorDecl *Constructor = + // dyn_cast<CXXConstructorDecl>(D)) { // ReturnType = Constructor->getThisType(S.getASTContext())->getPointeeType(); // //} else { |