Implement -Wshadow. Based on a patch by Mike M.!

llvm-svn: 98684
This commit is contained in:
John McCall 2010-03-16 21:48:18 +00:00
parent c953bca10b
commit a2a3f7dc11
5 changed files with 78 additions and 3 deletions

View 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">;

View File

@ -108,6 +108,15 @@ def warn_use_out_of_scope_declaration : Warning<
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">;

View File

@ -430,7 +430,10 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
for (; I!=End; ++I)
QualName += *I + "::";
if (getDeclName())
QualName += getNameAsString();
else
QualName += "<anonymous>";
return QualName;
}

View 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);

View 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.
///