Add some more code modification hints

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68261 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2009-04-01 23:51:29 +00:00
Родитель 78d8a089c8
Коммит a3a835149e
14 изменённых файлов: 116 добавлений и 35 удалений

Просмотреть файл

@ -60,5 +60,9 @@ page full of results (say, 50 lines of text). Beyond that, (1) the
remaining errors are likely to be less interesting, and (2) the poor
user has to scroll his terminal to find out where things went wrong.
//===---------------------------------------------------------------------===//
More ideas for code modification hints:
- If no member of a given name is found in a class/struct, search through the names of entities that do exist in the class and suggest the closest candidate. e.g., if I write "DS.setTypeSpecType", it would suggest "DS.SetTypeSpecType" (edit distance = 1).
- If a class member is defined out-of-line but isn't in the class declaration (and there are no close matches!), provide the option to add an in-class declaration.
- Fix-it hints for the inclusion of headers when needed for particular features (e.g., <typeinfo> for typeid)
- Change "foo.bar" to "foo->bar" when "foo" is a pointer.

Просмотреть файл

@ -258,7 +258,7 @@ def err_virtual_out_of_class : Error<
"'virtual' can only be specified inside the class definition">;
def err_static_not_bitfield : Error<"static member %0 cannot be a bit-field">;
def err_static_out_of_line : Error<
"'static' can not be specified on an out-of-line static member definition">;
"'static' can only be specified inside the class definition">;
def err_typedef_not_bitfield : Error<"typedef member %0 cannot be a bit-field">;
def err_not_integral_type_bitfield : Error<
"bit-field %0 has non-integral type %1">;
@ -465,7 +465,7 @@ def err_ident_list_in_fn_declaration : Error<
"a parameter list without types is only allowed in a function definition">;
def ext_param_not_declared : Extension<
"parameter %0 was not declared, defaulting to type 'int'">;
def ext_param_typedef_of_void : Extension<
def err_param_typedef_of_void : Error<
"empty parameter list defined with a typedef of 'void' not allowed in C++">;
def err_param_default_argument : Error<
"C does not support default arguments">;
@ -580,8 +580,6 @@ def err_template_arg_list_different_arity : Error<
"%select{too few|too many}0 template arguments for "
"%select{class template|function template|template template parameter"
"|template}1 %2">;
def note_template_decl_here : Note<"template is declared here">;
def note_member_of_template_here : Note<"member is declared here">;
def err_template_arg_must_be_type : Error<
@ -604,11 +602,9 @@ def note_template_arg_refers_here_func : Note<
def err_template_arg_template_params_mismatch : Error<
"template template argument has different template parameters than its "
"corresponding template template parameter">;
def err_template_arg_not_integral_or_enumeral : Error<
"non-type template argument of type %0 must have an integral or enumeration"
" type">;
def err_template_arg_not_ice : Error<
"non-type template argument of type %0 is not an integral constant "
"expression">;
@ -618,11 +614,9 @@ def err_template_arg_not_convertible : Error<
def err_template_arg_negative : Error<
"non-type template argument provides negative value '%0' for unsigned "
"template parameter of type %1">;
def err_template_arg_too_large : Error<
"non-type template argument value '%0' is too large for template "
"parameter of type %1">;
def err_template_arg_no_ref_bind : Error<
"non-type template parameter of reference type %0 cannot bind to template "
"argument of type %1">;

Просмотреть файл

@ -268,7 +268,8 @@ public:
/// been parsed prior to a function definition.
/// @param S The function prototype scope.
/// @param D The function declarator.
virtual void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D) {
virtual void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
SourceLocation LocAfterDecls) {
}
/// ActOnStartOfFunctionDef - This is called at the start of a function

Просмотреть файл

@ -740,7 +740,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
}
// The actions module must verify that all arguments were declared.
Actions.ActOnFinishKNRParamDeclarations(CurScope, D);
Actions.ActOnFinishKNRParamDeclarations(CurScope, D, Tok.getLocation());
}

Просмотреть файл

@ -368,7 +368,8 @@ public:
virtual void SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc);
virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, DeclPtrTy *Group,
unsigned NumDecls);
virtual void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D);
virtual void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
SourceLocation LocAfterDecls);
virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *S, Declarator &D);
virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *S, DeclPtrTy D);
virtual void ActOnStartOfObjCMethodDef(Scope *S, DeclPtrTy D);

Просмотреть файл

@ -2041,7 +2041,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// typedef of void is not permitted.
if (getLangOptions().CPlusPlus &&
Param->getType().getUnqualifiedType() != Context.VoidTy) {
Diag(Param->getLocation(), diag::ext_param_typedef_of_void);
Diag(Param->getLocation(), diag::err_param_typedef_of_void);
}
} else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) {
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
@ -2697,7 +2697,8 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
return DeclPtrTy::make(New);
}
void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D) {
void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
SourceLocation LocAfterDecls) {
assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
"Not a function declarator!");
DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
@ -2707,8 +2708,13 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D) {
if (!FTI.hasPrototype) {
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
if (FTI.ArgInfo[i].Param == 0) {
std::string Code = "int ";
Code += FTI.ArgInfo[i].Ident->getName();
Code += ";\n ";
Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared)
<< FTI.ArgInfo[i].Ident;
<< FTI.ArgInfo[i].Ident
<< CodeModificationHint::CreateInsertion(LocAfterDecls, Code);
// Implicitly declare the argument as type 'int' for lack of a better
// type.
DeclSpec DS;
@ -3215,13 +3221,29 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
// Make sure that this wasn't declared as an enum and now used as a
// struct or something similar.
if (PrevTagDecl->getTagKind() != Kind) {
Diag(KWLoc, diag::err_use_with_wrong_tag) << Name;
bool SafeToContinue
= (PrevTagDecl->getTagKind() != TagDecl::TK_enum &&
Kind != TagDecl::TK_enum);
if (SafeToContinue)
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< Name
<< CodeModificationHint::CreateReplacement(SourceRange(KWLoc),
PrevTagDecl->getKindName());
else
Diag(KWLoc, diag::err_use_with_wrong_tag) << Name;
Diag(PrevDecl->getLocation(), diag::note_previous_use);
// Recover by making this an anonymous redefinition.
Name = 0;
PrevDecl = 0;
Invalid = true;
} else {
if (SafeToContinue)
Kind = PrevTagDecl->getTagKind();
else {
// Recover by making this an anonymous redefinition.
Name = 0;
PrevDecl = 0;
Invalid = true;
}
}
if (!Invalid) {
// If this is a use, just return the declaration we found.
// FIXME: In the future, return a variant or some other clue

Просмотреть файл

@ -1307,8 +1307,9 @@ bool Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
QualType ParamType = Constructor->getParamDecl(0)->getType();
QualType ClassTy = Context.getTagDeclType(ClassDecl);
if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) {
Diag(Constructor->getLocation(), diag::err_constructor_byvalue_arg)
<< SourceRange(Constructor->getParamDecl(0)->getLocation());
SourceLocation ParamLoc = Constructor->getParamDecl(0)->getLocation();
Diag(ParamLoc, diag::err_constructor_byvalue_arg)
<< CodeModificationHint::CreateInsertion(ParamLoc, "const &");
Invalid = true;
}
}

Просмотреть файл

@ -3402,11 +3402,25 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
// operand is null), the user probably wants strcmp.
if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) &&
!RHSStripped->isNullPointerConstant(Context))
Diag(Loc, diag::warn_stringcompare) << lex->getSourceRange();
Diag(Loc, diag::warn_stringcompare)
<< lex->getSourceRange()
<< CodeModificationHint::CreateReplacement(SourceRange(Loc), ", ")
<< CodeModificationHint::CreateInsertion(lex->getLocStart(),
"strcmp(")
<< CodeModificationHint::CreateInsertion(
PP.getLocForEndOfToken(rex->getLocEnd()),
") == 0");
else if ((isa<StringLiteral>(RHSStripped) ||
isa<ObjCEncodeExpr>(RHSStripped)) &&
!LHSStripped->isNullPointerConstant(Context))
Diag(Loc, diag::warn_stringcompare) << rex->getSourceRange();
Diag(Loc, diag::warn_stringcompare)
<< rex->getSourceRange()
<< CodeModificationHint::CreateReplacement(SourceRange(Loc), ", ")
<< CodeModificationHint::CreateInsertion(lex->getLocStart(),
"strcmp(")
<< CodeModificationHint::CreateInsertion(
PP.getLocForEndOfToken(rex->getLocEnd()),
") == 0");
}
// The result of comparisons is 'bool' in C++, 'int' in C.

Просмотреть файл

@ -540,7 +540,9 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
if (T->isScalarType())
SemaRef.Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init)
<< IList->getSourceRange();
<< IList->getSourceRange()
<< CodeModificationHint::CreateRemoval(SourceRange(IList->getLocStart()))
<< CodeModificationHint::CreateRemoval(SourceRange(IList->getLocEnd()));
}
void InitListChecker::CheckListElementTypes(InitListExpr *IList,

Просмотреть файл

@ -462,12 +462,14 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
// template declaration (7.1.5.3).
RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl();
if (PrevRecordDecl->getTagKind() != Kind) {
Diag(KWLoc, diag::err_use_with_wrong_tag) << Name;
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< Name
<< CodeModificationHint::CreateReplacement(KWLoc,
PrevRecordDecl->getKindName());
Diag(PrevRecordDecl->getLocation(), diag::note_previous_use);
return true;
Kind = PrevRecordDecl->getTagKind();
}
// Check for redefinition of this class template.
if (TK == TK_Definition) {
if (TagDecl *Def = PrevRecordDecl->getDefinition(Context)) {
@ -1974,7 +1976,10 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
case DeclSpec::TST_class: Kind = TagDecl::TK_class; break;
}
if (ClassTemplate->getTemplatedDecl()->getTagKind() != Kind) {
Diag(KWLoc, diag::err_use_with_wrong_tag) << ClassTemplate;
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< ClassTemplate
<< CodeModificationHint::CreateReplacement(KWLoc,
ClassTemplate->getTemplatedDecl()->getKindName());
Diag(ClassTemplate->getTemplatedDecl()->getLocation(),
diag::note_previous_use);
Kind = ClassTemplate->getTemplatedDecl()->getTagKind();

10
test/Sema/fixit-errors.c Normal file
Просмотреть файл

@ -0,0 +1,10 @@
// RUN: clang-cc -fsyntax-only -pedantic -verify %s
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. Eventually,
we would like to actually try to perform the suggested
modifications and compile the result to test that no warnings
remain. */
struct s; // expected-note{{previous use is here}}
union s *s1; // expected-error{{use of 's' with tag type that does not match previous declaration}}

Просмотреть файл

@ -16,3 +16,14 @@ _Complex cd;
struct s s0 = { y: 5 };
int array0[5] = { [3] 3 };
void f1(x, y)
{
}
int i0 = { 17 };
int f2(const char *my_string) {
// FIXME: terminal output isn't so good when "my_string" is shorter
return my_string == "foo";
}

Просмотреть файл

@ -6,9 +6,25 @@
modifications and compile the result to test that no warnings
remain. */
struct C1 { };
struct C1 {
virtual void f();
static void g();
};
struct C2 : virtual public virtual C1 { }; // expected-error{{duplicate}}
template<int Value> struct CT { };
virtual void C1::f() { } // expected-error{{'virtual' can only be specified inside the class definition}}
static void C1::g() { } // expected-error{{'static' can only be specified inside the class definition}}
template<int Value> struct CT { }; // expected-note{{previous use is here}}
CT<10 >> 2> ct; // expected-warning{{require parentheses}}
class C3 {
public:
C3(C3, int i = 0); // expected-error{{copy constructor must pass its first argument by reference}}
};
struct CT<0> { }; // expected-error{{'template<>'}}
template<> class CT<1> { }; // expected-error{{tag type}}

Просмотреть файл

@ -18,12 +18,12 @@ A::undef1::undef2 ex4; // expected-error {{no member named 'undef1'}} expected-e
int A::C::Ag1() { return 0; }
static int A::C::Ag2() { return 0; } // expected-error{{'static' can not be specified on an out-of-line static member}}
static int A::C::Ag2() { return 0; } // expected-error{{'static' can}}
int A::C::cx = 17;
static int A::C::cx2 = 17; // expected-error{{'static' can not be specified on an out-of-line static member}}
static int A::C::cx2 = 17; // expected-error{{'static' can}}
class C2 {
void m(); // expected-note{{member declaration nearly matches}}