aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaStmt.cpp
diff options
context:
space:
mode:
authorRichard Trieu <rtrieu@google.com>2012-04-30 18:01:30 +0000
committerRichard Trieu <rtrieu@google.com>2012-04-30 18:01:30 +0000
commit694e796f462748ab4dc7ecdf4be5da44dd2c8c94 (patch)
tree2d286cc81d769fd4cf3db4ef1b27c3ff9732f0c6 /lib/Sema/SemaStmt.cpp
parentb4ee88060a5c277085ec6da9890e4c7da3651f86 (diff)
Add -Wloop-analysis. This warning will fire on for loops which the variables
in the loop conditional do not change. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@155835 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaStmt.cpp')
-rw-r--r--lib/Sema/SemaStmt.cpp216
1 files changed, 216 insertions, 0 deletions
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 252d3971dc..66ddbaabf1 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtObjC.h"
@@ -28,6 +29,7 @@
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
using namespace clang;
using namespace sema;
@@ -1037,6 +1039,218 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body,
return Owned(new (Context) DoStmt(Body, Cond, DoLoc, WhileLoc, CondRParen));
}
+namespace {
+ // This visitor will traverse a conditional statement and store all
+ // the evaluated decls into a vector. Simple is set to true if none
+ // of the excluded constructs are used.
+ class DeclExtractor : public EvaluatedExprVisitor<DeclExtractor> {
+ llvm::SmallPtrSet<VarDecl*, 8> &Decls;
+ llvm::SmallVector<SourceRange, 10> &Ranges;
+ bool Simple;
+ PartialDiagnostic &PDiag;
+public:
+ typedef EvaluatedExprVisitor<DeclExtractor> Inherited;
+
+ DeclExtractor(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls,
+ llvm::SmallVector<SourceRange, 10> &Ranges,
+ PartialDiagnostic &PDiag) :
+ Inherited(S.Context),
+ Decls(Decls),
+ Ranges(Ranges),
+ Simple(true),
+ PDiag(PDiag) {}
+
+ bool isSimple() { return Simple; }
+
+ // Replaces the method in EvaluatedExprVisitor.
+ void VisitMemberExpr(MemberExpr* E) {
+ Simple = false;
+ }
+
+ // Any Stmt not whitelisted will cause the condition to be marked complex.
+ void VisitStmt(Stmt *S) {
+ Simple = false;
+ }
+
+ void VisitBinaryOperator(BinaryOperator *E) {
+ Visit(E->getLHS());
+ Visit(E->getRHS());
+ }
+
+ void VisitCastExpr(CastExpr *E) {
+ Visit(E->getSubExpr());
+ }
+
+ void VisitUnaryOperator(UnaryOperator *E) {
+ // Skip checking conditionals with derefernces.
+ if (E->getOpcode() == UO_Deref)
+ Simple = false;
+ else
+ Visit(E->getSubExpr());
+ }
+
+ void VisitConditionalOperator(ConditionalOperator *E) {
+ Visit(E->getCond());
+ Visit(E->getTrueExpr());
+ Visit(E->getFalseExpr());
+ }
+
+ void VisitParenExpr(ParenExpr *E) {
+ Visit(E->getSubExpr());
+ }
+
+ void VisitBinaryConditionalOperator(BinaryConditionalOperator *E) {
+ Visit(E->getOpaqueValue()->getSourceExpr());
+ Visit(E->getFalseExpr());
+ }
+
+ void VisitIntegerLiteral(IntegerLiteral *E) { }
+ void VisitFloatingLiteral(FloatingLiteral *E) { }
+ void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { }
+ void VisitCharacterLiteral(CharacterLiteral *E) { }
+ void VisitGNUNullExpr(GNUNullExpr *E) { }
+ void VisitImaginaryLiteral(ImaginaryLiteral *E) { }
+
+ void VisitDeclRefExpr(DeclRefExpr *E) {
+ VarDecl *VD = dyn_cast<VarDecl>(E->getDecl());
+ if (!VD) return;
+
+ Ranges.push_back(E->getSourceRange());
+
+ Decls.insert(VD);
+ }
+
+ }; // end class DeclExtractor
+
+ // DeclMatcher checks to see if the decls are used in a non-evauluated
+ // context.
+ class DeclMatcher : public EvaluatedExprVisitor<DeclMatcher> {
+ llvm::SmallPtrSet<VarDecl*, 8> &Decls;
+ bool FoundDecl;
+ //bool EvalDecl;
+
+public:
+ typedef EvaluatedExprVisitor<DeclMatcher> Inherited;
+
+ DeclMatcher(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls, Stmt *Statement) :
+ Inherited(S.Context), Decls(Decls), FoundDecl(false) {
+ if (!Statement) return;
+
+ Visit(Statement);
+ }
+
+ void VisitReturnStmt(ReturnStmt *S) {
+ FoundDecl = true;
+ }
+
+ void VisitBreakStmt(BreakStmt *S) {
+ FoundDecl = true;
+ }
+
+ void VisitGotoStmt(GotoStmt *S) {
+ FoundDecl = true;
+ }
+
+ void VisitCastExpr(CastExpr *E) {
+ if (E->getCastKind() == CK_LValueToRValue)
+ CheckLValueToRValueCast(E->getSubExpr());
+ else
+ Visit(E->getSubExpr());
+ }
+
+ void CheckLValueToRValueCast(Expr *E) {
+ E = E->IgnoreParenImpCasts();
+
+ if (isa<DeclRefExpr>(E)) {
+ return;
+ }
+
+ if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ Visit(CO->getCond());
+ CheckLValueToRValueCast(CO->getTrueExpr());
+ CheckLValueToRValueCast(CO->getFalseExpr());
+ return;
+ }
+
+ if (BinaryConditionalOperator *BCO =
+ dyn_cast<BinaryConditionalOperator>(E)) {
+ CheckLValueToRValueCast(BCO->getOpaqueValue()->getSourceExpr());
+ CheckLValueToRValueCast(BCO->getFalseExpr());
+ return;
+ }
+
+ Visit(E);
+ }
+
+ void VisitDeclRefExpr(DeclRefExpr *E) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()))
+ if (Decls.count(VD))
+ FoundDecl = true;
+ }
+
+ bool FoundDeclInUse() { return FoundDecl; }
+
+ }; // end class DeclMatcher
+
+ void CheckForLoopConditionalStatement(Sema &S, Expr *Second,
+ Expr *Third, Stmt *Body) {
+ // Condition is empty
+ if (!Second) return;
+
+ if (S.Diags.getDiagnosticLevel(diag::warn_variables_not_in_loop_body,
+ Second->getLocStart())
+ == DiagnosticsEngine::Ignored)
+ return;
+
+ PartialDiagnostic PDiag = S.PDiag(diag::warn_variables_not_in_loop_body);
+ llvm::SmallPtrSet<VarDecl*, 8> Decls;
+ llvm::SmallVector<SourceRange, 10> Ranges;
+ DeclExtractor DE(S, Decls, Ranges, PDiag);
+ DE.Visit(Second);
+
+ // Don't analyze complex conditionals.
+ if (!DE.isSimple()) return;
+
+ // No decls found.
+ if (Decls.size() == 0) return;
+
+ // Don't warn on volatile decls.
+ for (llvm::SmallPtrSet<VarDecl*, 8>::iterator I = Decls.begin(),
+ E = Decls.end();
+ I != E; ++I)
+ if ((*I)->getType().isVolatileQualified()) return;
+
+ if (DeclMatcher(S, Decls, Second).FoundDeclInUse() ||
+ DeclMatcher(S, Decls, Third).FoundDeclInUse() ||
+ DeclMatcher(S, Decls, Body).FoundDeclInUse())
+ return;
+
+ // Load decl names into diagnostic.
+ if (Decls.size() > 4)
+ PDiag << 0;
+ else {
+ PDiag << Decls.size();
+ for (llvm::SmallPtrSet<VarDecl*, 8>::iterator I = Decls.begin(),
+ E = Decls.end();
+ I != E; ++I)
+ PDiag << (*I)->getDeclName();
+ }
+
+ // Load SourceRanges into diagnostic if there is room.
+ // Otherwise, load the SourceRange of the conditional expression.
+ if (Ranges.size() <= PartialDiagnostic::MaxArguments)
+ for (llvm::SmallVector<SourceRange, 10>::iterator I = Ranges.begin(),
+ E = Ranges.end();
+ I != E; ++I)
+ PDiag << *I;
+ else
+ PDiag << Second->getSourceRange();
+
+ S.Diag(Ranges.begin()->getBegin(), PDiag);
+ }
+
+} // end namespace
+
StmtResult
Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
Stmt *First, FullExprArg second, Decl *secondVar,
@@ -1059,6 +1273,8 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
}
}
+ CheckForLoopConditionalStatement(*this, second.get(), third.get(), Body);
+
ExprResult SecondResult(second.release());
VarDecl *ConditionVar = 0;
if (secondVar) {