Implement -Wshadow. Based on a patch by Mike M.!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98684 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index f568d1c..6c9a45e 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -430,7 +430,10 @@
for (; I!=End; ++I)
QualName += *I + "::";
- QualName += getNameAsString();
+ if (getDeclName())
+ QualName += getNameAsString();
+ else
+ QualName += "<anonymous>";
return QualName;
}
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index c6b6367..a18d5f1 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -778,6 +778,7 @@
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);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 776f0dd..5db8171 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2403,6 +2403,9 @@
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 @@
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.
///