summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
diff options
context:
space:
mode:
authorArtem Dergachev <artem.dergachev@gmail.com>2018-02-27 22:05:55 +0000
committerArtem Dergachev <artem.dergachev@gmail.com>2018-02-27 22:05:55 +0000
commitf119bf99e59f22c1ec7bb51478d671ce4bcc8f7e (patch)
tree476fdb8117e34127ce77eedfe5b96e2cb7f16f02 /clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
parent8edd70b7c6cff63c9c8081b172115403ee189a3b (diff)
downloadbcm5719-llvm-f119bf99e59f22c1ec7bb51478d671ce4bcc8f7e.tar.gz
bcm5719-llvm-f119bf99e59f22c1ec7bb51478d671ce4bcc8f7e.zip
[analyzer] UndefinedAssignmentChecker: Better warning message in implicit ctors.
When a class forgets to initialize a field in the constructor, and then gets copied around, a warning is emitted that the value assigned to a specific field is undefined. When the copy/move constructor is implicit (not written out in the code) but not trivial (is not a trivial memory copy, eg. because members have an explicit copy constructor), the body of such constructor is auto-generated in the AST. In this case the checker's warning message is squeezed at the top of the class declaration, and it gets hard to guess which field is at fault. Fix the warning message to include the name of the field. Differential Revision: https://reviews.llvm.org/D43798 llvm-svn: 326258
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp31
1 files changed, 25 insertions, 6 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index 52b4ca7d770..2ef6855ba6b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
@@ -51,17 +51,20 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
if (!N)
return;
- const char *str = "Assigned value is garbage or undefined";
-
+ static const char *const DefaultMsg =
+ "Assigned value is garbage or undefined";
if (!BT)
- BT.reset(new BuiltinBug(this, str));
+ BT.reset(new BuiltinBug(this, DefaultMsg));
// Generate a report for this bug.
+ llvm::SmallString<128> Str;
+ llvm::raw_svector_ostream OS(Str);
+
const Expr *ex = nullptr;
while (StoreE) {
if (const UnaryOperator *U = dyn_cast<UnaryOperator>(StoreE)) {
- str = "The expression is an uninitialized value. "
+ OS << "The expression is an uninitialized value. "
"The computed value will also be garbage";
ex = U->getSubExpr();
@@ -71,7 +74,7 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) {
if (B->isCompoundAssignmentOp()) {
if (C.getSVal(B->getLHS()).isUndef()) {
- str = "The left expression of the compound assignment is an "
+ OS << "The left expression of the compound assignment is an "
"uninitialized value. The computed value will also be garbage";
ex = B->getLHS();
break;
@@ -87,10 +90,26 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
ex = VD->getInit();
}
+ if (const auto *CD =
+ dyn_cast<CXXConstructorDecl>(C.getStackFrame()->getDecl())) {
+ if (CD->isImplicit()) {
+ for (auto I : CD->inits()) {
+ if (I->getInit()->IgnoreImpCasts() == StoreE) {
+ OS << "Value assigned to field '" << I->getMember()->getName()
+ << "' in implicit constructor is garbage or undefined";
+ break;
+ }
+ }
+ }
+ }
+
break;
}
- auto R = llvm::make_unique<BugReport>(*BT, str, N);
+ if (OS.str().empty())
+ OS << DefaultMsg;
+
+ auto R = llvm::make_unique<BugReport>(*BT, OS.str(), N);
if (ex) {
R->addRange(ex->getSourceRange());
bugreporter::trackNullOrUndefValue(N, ex, *R);
OpenPOWER on IntegriCloud