зеркало из https://github.com/microsoft/clang-1.git
Avoid correcting unknown identifiers to types where types aren't allowed.
Pass a typo correction callback object from ParseCastExpr to Sema::ActOnIdExpression to be a bit more selective about what kinds of corrections will be allowed for unknown identifiers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148973 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
ada4fa7978
Коммит
cd78e612d6
|
@ -1260,10 +1260,17 @@ private:
|
|||
//===--------------------------------------------------------------------===//
|
||||
// C99 6.5: Expressions.
|
||||
|
||||
ExprResult ParseExpression();
|
||||
/// TypeCastState - State whether an expression is or may be a type cast.
|
||||
enum TypeCastState {
|
||||
NotTypeCast = 0,
|
||||
MaybeTypeCast,
|
||||
IsTypeCast
|
||||
};
|
||||
|
||||
ExprResult ParseExpression(TypeCastState isTypeCast = NotTypeCast);
|
||||
ExprResult ParseConstantExpression();
|
||||
// Expr that doesn't include commas.
|
||||
ExprResult ParseAssignmentExpression();
|
||||
ExprResult ParseAssignmentExpression(TypeCastState isTypeCast = NotTypeCast);
|
||||
|
||||
ExprResult ParseExpressionWithLeadingAt(SourceLocation AtLoc);
|
||||
|
||||
|
@ -1274,10 +1281,10 @@ private:
|
|||
ExprResult ParseCastExpression(bool isUnaryExpression,
|
||||
bool isAddressOfOperand,
|
||||
bool &NotCastExpr,
|
||||
bool isTypeCast);
|
||||
TypeCastState isTypeCast);
|
||||
ExprResult ParseCastExpression(bool isUnaryExpression,
|
||||
bool isAddressOfOperand = false,
|
||||
bool isTypeCast = false);
|
||||
TypeCastState isTypeCast = NotTypeCast);
|
||||
|
||||
/// Returns true if the next token would start a postfix-expression
|
||||
/// suffix.
|
||||
|
|
|
@ -2291,7 +2291,8 @@ public:
|
|||
SourceRange getExprRange(Expr *E) const;
|
||||
|
||||
ExprResult ActOnIdExpression(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Id,
|
||||
bool HasTrailingLParen, bool IsAddressOfOperand);
|
||||
bool HasTrailingLParen, bool IsAddressOfOperand,
|
||||
CorrectionCandidateCallback *CCC = 0);
|
||||
|
||||
void DecomposeUnqualifiedId(const UnqualifiedId &Id,
|
||||
TemplateArgumentListInfo &Buffer,
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "clang/Sema/DeclSpec.h"
|
||||
#include "clang/Sema/Scope.h"
|
||||
#include "clang/Sema/ParsedTemplate.h"
|
||||
#include "clang/Sema/TypoCorrection.h"
|
||||
#include "clang/Basic/PrettyStackTrace.h"
|
||||
#include "RAIIObjectsForParser.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
@ -174,8 +175,8 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
|
|||
/// expression: [C99 6.5.17]
|
||||
/// assignment-expression ...[opt]
|
||||
/// expression ',' assignment-expression ...[opt]
|
||||
ExprResult Parser::ParseExpression() {
|
||||
ExprResult LHS(ParseAssignmentExpression());
|
||||
ExprResult Parser::ParseExpression(TypeCastState isTypeCast) {
|
||||
ExprResult LHS(ParseAssignmentExpression(isTypeCast));
|
||||
return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
|
||||
}
|
||||
|
||||
|
@ -211,7 +212,7 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
|
|||
}
|
||||
|
||||
/// ParseAssignmentExpression - Parse an expr that doesn't include commas.
|
||||
ExprResult Parser::ParseAssignmentExpression() {
|
||||
ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) {
|
||||
if (Tok.is(tok::code_completion)) {
|
||||
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression);
|
||||
cutOffParsing();
|
||||
|
@ -221,7 +222,9 @@ ExprResult Parser::ParseAssignmentExpression() {
|
|||
if (Tok.is(tok::kw_throw))
|
||||
return ParseThrowExpression();
|
||||
|
||||
ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false);
|
||||
ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false,
|
||||
/*isAddressOfOperand=*/false,
|
||||
isTypeCast);
|
||||
return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment);
|
||||
}
|
||||
|
||||
|
@ -417,7 +420,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
|
|||
///
|
||||
ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
||||
bool isAddressOfOperand,
|
||||
bool isTypeCast) {
|
||||
TypeCastState isTypeCast) {
|
||||
bool NotCastExpr;
|
||||
ExprResult Res = ParseCastExpression(isUnaryExpression,
|
||||
isAddressOfOperand,
|
||||
|
@ -428,6 +431,29 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
|||
return move(Res);
|
||||
}
|
||||
|
||||
namespace {
|
||||
class CastExpressionIdValidator : public CorrectionCandidateCallback {
|
||||
public:
|
||||
CastExpressionIdValidator(bool AllowTypes, bool AllowNonTypes)
|
||||
: AllowNonTypes(AllowNonTypes) {
|
||||
WantTypeSpecifiers = AllowTypes;
|
||||
}
|
||||
|
||||
virtual bool ValidateCandidate(const TypoCorrection &candidate) {
|
||||
NamedDecl *ND = candidate.getCorrectionDecl();
|
||||
if (!ND)
|
||||
return candidate.isKeyword();
|
||||
|
||||
if (isa<TypeDecl>(ND))
|
||||
return WantTypeSpecifiers;
|
||||
return AllowNonTypes;
|
||||
}
|
||||
|
||||
private:
|
||||
bool AllowNonTypes;
|
||||
};
|
||||
}
|
||||
|
||||
/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is
|
||||
/// true, parse a unary-expression. isAddressOfOperand exists because an
|
||||
/// id-expression that is the operand of address-of gets special treatment
|
||||
|
@ -592,7 +618,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
|||
ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
||||
bool isAddressOfOperand,
|
||||
bool &NotCastExpr,
|
||||
bool isTypeCast) {
|
||||
TypeCastState isTypeCast) {
|
||||
ExprResult Res;
|
||||
tok::TokenKind SavedKind = Tok.getKind();
|
||||
NotCastExpr = false;
|
||||
|
@ -623,7 +649,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
|||
ColonProtectionRAIIObject X(*this, false);
|
||||
|
||||
Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
|
||||
isTypeCast, CastTy, RParenLoc);
|
||||
isTypeCast == IsTypeCast, CastTy, RParenLoc);
|
||||
}
|
||||
|
||||
switch (ParenExprType) {
|
||||
|
@ -769,9 +795,12 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
|||
// not.
|
||||
UnqualifiedId Name;
|
||||
CXXScopeSpec ScopeSpec;
|
||||
CastExpressionIdValidator Validator(isTypeCast != NotTypeCast,
|
||||
isTypeCast != IsTypeCast);
|
||||
Name.setIdentifier(&II, ILoc);
|
||||
Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, Name,
|
||||
Tok.is(tok::l_paren), isAddressOfOperand);
|
||||
Tok.is(tok::l_paren), isAddressOfOperand,
|
||||
&Validator);
|
||||
break;
|
||||
}
|
||||
case tok::char_constant: // constant: character-constant
|
||||
|
@ -1954,7 +1983,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
|
|||
// TODO: For cast expression with CastTy.
|
||||
Result = ParseCastExpression(/*isUnaryExpression=*/false,
|
||||
/*isAddressOfOperand=*/false,
|
||||
/*isTypeCast=*/true);
|
||||
/*isTypeCast=*/IsTypeCast);
|
||||
if (!Result.isInvalid()) {
|
||||
Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc,
|
||||
DeclaratorInfo, CastTy,
|
||||
|
@ -1981,7 +2010,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
|
|||
} else {
|
||||
InMessageExpressionRAIIObject InMessage(*this, false);
|
||||
|
||||
Result = ParseExpression();
|
||||
Result = ParseExpression(MaybeTypeCast);
|
||||
ExprType = SimpleExpr;
|
||||
|
||||
// Don't build a paren expression unless we actually match a ')'.
|
||||
|
|
|
@ -2552,7 +2552,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
|
|||
false/*isAddressofOperand*/,
|
||||
NotCastExpr,
|
||||
// type-id has priority.
|
||||
true/*isTypeCast*/);
|
||||
IsTypeCast);
|
||||
}
|
||||
|
||||
// If we parsed a cast-expression, it's really a type-id, otherwise it's
|
||||
|
|
|
@ -1704,7 +1704,8 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
|
|||
CXXScopeSpec &SS,
|
||||
UnqualifiedId &Id,
|
||||
bool HasTrailingLParen,
|
||||
bool IsAddressOfOperand) {
|
||||
bool IsAddressOfOperand,
|
||||
CorrectionCandidateCallback *CCC) {
|
||||
assert(!(IsAddressOfOperand && HasTrailingLParen) &&
|
||||
"cannot be direct & operand and have a trailing lparen");
|
||||
|
||||
|
@ -1819,7 +1820,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
|
|||
TemplateArgs);
|
||||
|
||||
CorrectionCandidateCallback DefaultValidator;
|
||||
if (DiagnoseEmptyLookup(S, SS, R, DefaultValidator))
|
||||
if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator))
|
||||
return ExprError();
|
||||
|
||||
assert(!R.empty() &&
|
||||
|
|
|
@ -114,6 +114,18 @@ struct TestRedecl : public BaseDecl {
|
|||
};
|
||||
void TestRedecl::add_in(int i) {} // expected-error{{out-of-line definition of 'add_in' does not match any declaration in 'TestRedecl'; did you mean 'add_it'?}}
|
||||
|
||||
// Test the improved typo correction for the Parser::ParseCastExpr =>
|
||||
// Sema::ActOnIdExpression => Sema::DiagnoseEmptyLookup call path.
|
||||
class SomeNetMessage;
|
||||
class Message {};
|
||||
void foo(Message&);
|
||||
void foo(SomeNetMessage&);
|
||||
void doit(void *data) {
|
||||
Message somenetmsg; // expected-note{{'somenetmsg' declared here}}
|
||||
foo(somenetmessage); // expected-error{{use of undeclared identifier 'somenetmessage'; did you mean 'somenetmsg'?}}
|
||||
foo((somenetmessage)data); // expected-error{{use of undeclared identifier 'somenetmessage'; did you mean 'SomeNetMessage'?}}
|
||||
}
|
||||
|
||||
// Test the typo-correction callback in BuildRecoveryCallExpr.
|
||||
// Solves the main issue in PR 9320 of suggesting corrections that take the
|
||||
// wrong number of arguments.
|
||||
|
|
Загрузка…
Ссылка в новой задаче