]> granicus.if.org Git - clang/commitdiff
Warn on self-assignment to member variables. PR13104.
authorNico Weber <nicolasweber@gmx.de>
Thu, 28 Jun 2012 23:53:12 +0000 (23:53 +0000)
committerNico Weber <nicolasweber@gmx.de>
Thu, 28 Jun 2012 23:53:12 +0000 (23:53 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159394 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaExpr.cpp
test/Sema/warn-self-assign-memvar.mm [new file with mode: 0644]
test/SemaObjC/provisional-ivar-lookup.m

index a99eb1d486de1aa94011cac881c5bdfbf5fe5bf3..ab2cd1b08be5c0b28c601b9c2ec502e41a0e17cc 100644 (file)
@@ -169,7 +169,8 @@ def ReturnTypeCLinkage : DiagGroup<"return-type-c-linkage">;
 def ReturnType : DiagGroup<"return-type", [ReturnTypeCLinkage]>;
 def BindToTemporaryCopy : DiagGroup<"bind-to-temporary-copy",
                                     [CXX98CompatBindToTemporaryCopy]>;
-def SelfAssignment : DiagGroup<"self-assign">;
+def SelfAssignmentMemvar : DiagGroup<"self-assign-memvar">;
+def SelfAssignment : DiagGroup<"self-assign", [SelfAssignmentMemvar]>;
 def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">;
 def Sentinel : DiagGroup<"sentinel">;
 def MissingMethodReturnType : DiagGroup<"missing-method-return-type">;
index 91f90ca19e28bd7d2c70ade7799076132140b3d3..0b3a8ed6987eae3fdea6676c49677d3bf96f983d 100644 (file)
@@ -5274,6 +5274,10 @@ def warn_stringcompare : Warning<
   "unspecified (use strncmp instead)">,
   InGroup<DiagGroup<"string-compare">>;
 
+def warn_identity_memvar_assign : Warning<
+  "assigning %select{member variable|instance variable}0 to itself">,
+  InGroup<SelfAssignmentMemvar>;
+
 // Generic selections.
 def err_assoc_type_incomplete : Error<
   "type %0 in generic association incomplete">;
index a6051d6ccc06609d576e63bae1b7dd4e780728fb..cd3c93b720d5ce92cb3d68b1c17e39cdf02cd932 100644 (file)
@@ -7558,7 +7558,27 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
   return true;
 }
 
+static void CheckIdentityMemvarAssignment(Expr *LHSExpr, Expr *RHSExpr,
+                                          SourceLocation Loc,
+                                          Sema &Sema) {
+  // C / C++ memvars
+  MemberExpr *ML = dyn_cast<MemberExpr>(LHSExpr);
+  MemberExpr *MR = dyn_cast<MemberExpr>(RHSExpr);
+  if (ML && MR && ML->getMemberDecl() == MR->getMemberDecl()) {
+    if (isa<CXXThisExpr>(ML->getBase()) && isa<CXXThisExpr>(MR->getBase()))
+      Sema.Diag(Loc, diag::warn_identity_memvar_assign) << 0;
+  }
 
+  // Objective-C memvars
+  ObjCIvarRefExpr *OL = dyn_cast<ObjCIvarRefExpr>(LHSExpr);
+  ObjCIvarRefExpr *OR = dyn_cast<ObjCIvarRefExpr>(RHSExpr);
+  if (OL && OR && OL->getDecl() == OR->getDecl()) {
+    DeclRefExpr *RL = dyn_cast<DeclRefExpr>(OL->getBase()->IgnoreImpCasts());
+    DeclRefExpr *RR = dyn_cast<DeclRefExpr>(OR->getBase()->IgnoreImpCasts());
+    if (RL && RR && RL->getDecl() == RR->getDecl())
+      Sema.Diag(Loc, diag::warn_identity_memvar_assign) << 1;
+  }
+}
 
 // C99 6.5.16.1
 QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
@@ -7575,6 +7595,10 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
                                              CompoundType;
   AssignConvertType ConvTy;
   if (CompoundType.isNull()) {
+    Expr *RHSCheck = RHS.get();
+
+    CheckIdentityMemvarAssignment(LHSExpr, RHSCheck, Loc, *this);
+
     QualType LHSTy(LHSType);
     ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS);
     if (RHS.isInvalid())
@@ -7595,7 +7619,6 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
     // If the RHS is a unary plus or minus, check to see if they = and + are
     // right next to each other.  If so, the user may have typo'd "x =+ 4"
     // instead of "x += 4".
-    Expr *RHSCheck = RHS.get();
     if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(RHSCheck))
       RHSCheck = ICE->getSubExpr();
     if (UnaryOperator *UO = dyn_cast<UnaryOperator>(RHSCheck)) {
diff --git a/test/Sema/warn-self-assign-memvar.mm b/test/Sema/warn-self-assign-memvar.mm
new file mode 100644 (file)
index 0000000..8c6fb0a
--- /dev/null
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+class S {
+ public:
+  int a_;
+  void s(int a) {
+    a_ = a_;  // expected-warning {{assigning member variable to itself}}
+
+    // Don't really care about this one either way.
+    this->a_ = a_;  // expected-warning {{assigning member variable to itself}}
+
+    a_ += a_;  // Shouldn't warn.
+  }
+};
+
+void f0(S* s) {
+  // Would be nice to have, but not important.
+  s->a_ = s->a_;
+}
+
+void f1(S* s, S* t) {
+  // Shouldn't warn.
+  t->a_ = s->a_;
+}
+
+struct T {
+  S* s_;
+};
+
+void f2(T* t) {
+  // Would be nice to have, but even less important.
+  t->s_->a_ = t->s_->a_;
+}
+
+void f3(T* t, T* t2) {
+  // Shouldn't warn.
+  t2->s_->a_ = t->s_->a_;
+}
+
+void f4(int i) {
+  // This is a common pattern to silence "parameter unused". Shouldn't warn.
+  i = i;
+
+  int j = 0;
+  j = j;  // Likewise.
+}
+
+@interface I {
+  int a_;
+}
+@end
+
+@implementation I
+- (void)setA:(int)a {
+  a_ = a_;  // expected-warning {{assigning instance variable to itself}}
+}
+
+- (void)foo:(I*)i {
+  // Don't care much about this warning.
+  i->a_ = i->a_;  // expected-warning {{assigning instance variable to itself}}
+
+  // Shouldn't warn.
+  a_ = i->a_;
+  i->a_ = a_;
+}
+@end
index 2ec23a55c37cb4752b6b4e566687e040f8f2cce9..7460fc2e206764590add9549b611f1d101b46349 100644 (file)
@@ -36,7 +36,7 @@
 
 @synthesize PROP=PROP;
 - (void)setPROP:(int)value {
-    PROP = PROP;        // OK
+    PROP = value;        // OK
 }
 
 @end