]> granicus.if.org Git - clang/commitdiff
Implement -Wshadow. Based on a patch by Mike M.!
authorJohn McCall <rjmccall@apple.com>
Tue, 16 Mar 2010 21:48:18 +0000 (21:48 +0000)
committerJohn McCall <rjmccall@apple.com>
Tue, 16 Mar 2010 21:48:18 +0000 (21:48 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98684 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/Decl.cpp
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp

index e5793fa58b04b9e488346c243ae85406f5a8b3d7..203ab1eed5473b69ec54406ab279178217070e1c 100644 (file)
@@ -73,7 +73,7 @@ def : DiagGroup<"redundant-decls">;
 def ReturnType : DiagGroup<"return-type">;
 def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">;
 def : DiagGroup<"sequence-point">;
-def : DiagGroup<"shadow">;
+def Shadow : DiagGroup<"shadow">;
 def : DiagGroup<"shorten-64-to-32">;
 def SignCompare : DiagGroup<"sign-compare">;
 def : DiagGroup<"synth">;
index 9a9b7cc85f6aa98075150c4081ec8948b3c50972..b2b4306bfa8703e85ef1d2aebca246564ec6b15f 100644 (file)
@@ -107,7 +107,16 @@ def warn_use_out_of_scope_declaration : Warning<
   "use of out-of-scope declaration of %0">;
 def err_inline_non_function : Error<
   "'inline' can only appear on functions">;
-  
+
+def warn_decl_shadow :
+  Warning<"declaration shadows a %select{"
+          "local variable|"
+          "variable in %2|"
+          "static data member of %2|"
+          "field of %2|"
+          "global built-in function}1">,
+  InGroup<Shadow>, DefaultIgnore;
+
 // C++ using declarations
 def err_using_requires_qualname : Error<
   "using declaration requires a qualified name">;
index f568d1cdd45e4f8614e81a7ef35cea688dbead8a..6c9a45ef6c44f94c2b37de66796a1389e100e408 100644 (file)
@@ -430,7 +430,10 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
   for (; I!=End; ++I)
     QualName += *I + "::";
 
-  QualName += getNameAsString();
+  if (getDeclName())
+    QualName += getNameAsString();
+  else
+    QualName += "<anonymous>";
 
   return QualName;
 }
index c6b63673f57abf2a417c4ec49e49a438712cb976..a18d5f11af39486a68d8052e49e9432d1457b125 100644 (file)
@@ -778,6 +778,7 @@ public:
                                         const LookupResult &Previous,
                                         Scope *S);
   void DiagnoseFunctionSpecifiers(Declarator& D);
+  void DiagnoseShadow(NamedDecl* D, const LookupResult& R);
   NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
                                     QualType R, TypeSourceInfo *TInfo,
                                     LookupResult &Previous, bool &Redeclaration);
index 776f0ddf1a61e662fa050c566b685e54f7620318..5db817192f68e7b53fa745d2cf3a5b4e62c0ad88 100644 (file)
@@ -2403,6 +2403,9 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
     NewVD->addAttr(::new (Context) AsmLabelAttr(Context, SE->getString()));
   }
 
+  // Diagnose shadowed variables before filtering for scope.
+  DiagnoseShadow(NewVD, Previous);
+
   // Don't consider existing declarations that are in a different
   // scope and are out-of-semantic-context declarations (if the new
   // declaration has linkage).
@@ -2454,6 +2457,65 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
   return NewVD;
 }
 
+/// \brief Diagnose variable or built-in function shadowing.
+///
+/// This method is called as soon as a NamedDecl materializes to check
+/// if it shadows another local or global variable, or a built-in function.
+///
+/// For performance reasons, the lookup results are reused from the calling
+/// context.
+///
+/// \param D variable decl to diagnose. Must be a variable.
+/// \param R cached previous lookup of \p D.
+///
+void Sema::DiagnoseShadow(NamedDecl* D, const LookupResult& R) {
+  assert(D->getKind() == Decl::Var && "Expecting variable.");
+
+  // Return if warning is ignored.
+  if (Diags.getDiagnosticLevel(diag::warn_decl_shadow) == Diagnostic::Ignored)
+    return;
+
+  // Return if not local decl.
+  if (!D->getDeclContext()->isFunctionOrMethod())
+    return;
+
+  DeclarationName Name = D->getDeclName();
+
+  // Return if lookup has no result.
+  if (R.getResultKind() != LookupResult::Found) {
+    // Emit warning for built-in shadowing.
+    if (Name.getAsIdentifierInfo() &&
+        Name.getAsIdentifierInfo()->getBuiltinID())
+      Diag(D->getLocation(), diag::warn_decl_shadow)
+        << Name
+        << 4 // global builtin
+        << Context.getTranslationUnitDecl();
+    return;
+  }
+
+  // Return if not variable decl.
+  NamedDecl* ShadowedDecl = R.getFoundDecl();
+  if (!isa<VarDecl>(ShadowedDecl) && !isa<FieldDecl>(ShadowedDecl))
+    return;
+
+  // Determine kind of declaration.
+  DeclContext *DC = ShadowedDecl->getDeclContext();
+  unsigned Kind;
+  if (isa<RecordDecl>(DC)) {
+    if (isa<FieldDecl>(ShadowedDecl))
+      Kind = 3; // field
+    else
+      Kind = 2; // static data member
+  } else if (DC->isFileContext())
+    Kind = 1; // global
+  else
+    Kind = 0; // local
+
+  // Emit warning and note.
+  Diag(D->getLocation(), diag::warn_decl_shadow) << Name << Kind << DC;
+  Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
+}
+
 /// \brief Perform semantic checking on a newly-created variable
 /// declaration.
 ///