зеркало из https://github.com/microsoft/clang.git
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:
Родитель
78d8a089c8
Коммит
a3a835149e
8
TODO.txt
8
TODO.txt
|
@ -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();
|
||||
|
|
|
@ -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}}
|
||||
|
|
Загрузка…
Ссылка в новой задаче