Add fixits for memory access warnings.
Also, do not display the builtin name and macro expansion when the
function is a builtin.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@157659 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 98e387b..483145b 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -331,7 +331,7 @@
 def note_bad_memaccess_silence : Note<
   "explicitly cast the pointer to silence this warning">;
 def warn_sizeof_pointer_expr_memaccess : Warning<
-  "argument to 'sizeof' in %0 call is the same expression as the "
+  "argument to 'sizeof' in '%0' call is the same expression as the "
   "%select{destination|source}1; did you mean to "
   "%select{dereference it|remove the addressof|provide an explicit length}2?">,
   InGroup<DiagGroup<"sizeof-pointer-memaccess">>;
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 7697054..004e994 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -2755,19 +2755,49 @@
           // TODO: For strncpy() and friends, this could suggest sizeof(dst)
           //       over sizeof(src) as well.
           unsigned ActionIdx = 0; // Default is to suggest dereferencing.
+          FixItHint Fixit = FixItHint(); // Default hint.
+          StringRef ReadableName = FnName->getName();
+
+          if (isa<DeclRefExpr>(SizeOfArg))
+            Fixit = FixItHint::CreateInsertion(SizeOfArg->getLocStart(), "*");
+
           if (const UnaryOperator *UnaryOp = dyn_cast<UnaryOperator>(Dest))
-            if (UnaryOp->getOpcode() == UO_AddrOf)
+            if (UnaryOp->getOpcode() == UO_AddrOf) {
+              Fixit = FixItHint::CreateRemoval(
+                      CharSourceRange::getTokenRange(SizeOfArg->getLocStart(),
+                                                     SizeOfArg->getLocStart()));
               ActionIdx = 1; // If its an address-of operator, just remove it.
+            }
           if (Context.getTypeSize(PointeeTy) == Context.getCharWidth())
             ActionIdx = 2; // If the pointee's size is sizeof(char),
                            // suggest an explicit length.
           unsigned DestSrcSelect =
             (BId == Builtin::BIstrndup ? 1 : ArgIdx);
-          DiagRuntimeBehavior(SizeOfArg->getExprLoc(), Dest,
+
+          // If the function is defined as a builtin macro, do not show macro
+          // expansion.
+          SourceLocation SL = SizeOfArg->getExprLoc();
+          SourceRange DSR = Dest->getSourceRange();
+          SourceRange SSR = SizeOfArg->getSourceRange();
+          SourceManager &SM  = PP.getSourceManager();
+
+          if (SM.isMacroArgExpansion(SL)) {
+            ReadableName = Lexer::getImmediateMacroName(SL, SM, LangOpts);
+            SL = SM.getSpellingLoc(SL);
+            DSR = SourceRange(SM.getSpellingLoc(DSR.getBegin()),
+                             SM.getSpellingLoc(DSR.getEnd()));
+            SSR = SourceRange(SM.getSpellingLoc(SSR.getBegin()),
+                             SM.getSpellingLoc(SSR.getEnd()));
+          }
+
+          DiagRuntimeBehavior(SL, Dest,
                               PDiag(diag::warn_sizeof_pointer_expr_memaccess)
-                                << FnName << DestSrcSelect << ActionIdx
-                                << Dest->getSourceRange()
-                                << SizeOfArg->getSourceRange());
+                                << ReadableName
+                                << DestSrcSelect
+                                << ActionIdx
+                                << DSR
+                                << SSR
+                                << Fixit);
           break;
         }
       }
diff --git a/test/SemaCXX/warn-memset-bad-sizeof-fixit.cpp b/test/SemaCXX/warn-memset-bad-sizeof-fixit.cpp
new file mode 100644
index 0000000..f76f497
--- /dev/null
+++ b/test/SemaCXX/warn-memset-bad-sizeof-fixit.cpp
@@ -0,0 +1,24 @@
+// RUN: cp %s %t
+// RUN: not %clang_cc1 -fixit -Werror -x c++ -std=c++98 %t
+// RUN: %clang_cc1 -fsyntax-only -Werror -x c++ -std=c++98 %t
+// RUN: cp %s %t
+// RUN: not %clang_cc1 -DUSE_BUILTINS -fixit -Werror -x c++ -std=c++98 %t
+// RUN: %clang_cc1 -DUSE_BUILTINS -fsyntax-only -Werror -x c++ -std=c++98 %t
+
+extern "C" void *memcpy(void *s1, const void *s2, unsigned n);
+
+#ifdef USE_BUILTINS
+# define BUILTIN(f) __builtin_ ## f
+#else
+# define BUILTIN(f) f
+#endif
+
+#define memcpy BUILTIN(memcpy)
+
+int testFixits(int *to, int *from) {
+  memcpy(to, from, sizeof(to)); // \
+         // expected-warning {{argument to 'sizeof' in 'memcpy' call is the same expression as the destination; did you mean to dereference it?}}
+  memcpy(0, &from, sizeof(&from)); // \
+         // expected-warning {{argument to 'sizeof' in 'memcpy' call is the same expression as the source; did you mean to remove the addressof?}}
+  return 0;
+}