Skip to content

Commit 77e21fc

Browse files
author
Kaelyn Uhrain
committed
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. llvm-svn: 148973
1 parent 8d24390 commit 77e21fc

File tree

6 files changed

+68
-18
lines changed

6 files changed

+68
-18
lines changed

clang/include/clang/Parse/Parser.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,10 +1260,17 @@ class Parser : public CodeCompletionHandler {
12601260
//===--------------------------------------------------------------------===//
12611261
// C99 6.5: Expressions.
12621262

1263-
ExprResult ParseExpression();
1263+
/// TypeCastState - State whether an expression is or may be a type cast.
1264+
enum TypeCastState {
1265+
NotTypeCast = 0,
1266+
MaybeTypeCast,
1267+
IsTypeCast
1268+
};
1269+
1270+
ExprResult ParseExpression(TypeCastState isTypeCast = NotTypeCast);
12641271
ExprResult ParseConstantExpression();
12651272
// Expr that doesn't include commas.
1266-
ExprResult ParseAssignmentExpression();
1273+
ExprResult ParseAssignmentExpression(TypeCastState isTypeCast = NotTypeCast);
12671274

12681275
ExprResult ParseExpressionWithLeadingAt(SourceLocation AtLoc);
12691276

@@ -1274,10 +1281,10 @@ class Parser : public CodeCompletionHandler {
12741281
ExprResult ParseCastExpression(bool isUnaryExpression,
12751282
bool isAddressOfOperand,
12761283
bool &NotCastExpr,
1277-
bool isTypeCast);
1284+
TypeCastState isTypeCast);
12781285
ExprResult ParseCastExpression(bool isUnaryExpression,
12791286
bool isAddressOfOperand = false,
1280-
bool isTypeCast = false);
1287+
TypeCastState isTypeCast = NotTypeCast);
12811288

12821289
/// Returns true if the next token would start a postfix-expression
12831290
/// suffix.

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2291,7 +2291,8 @@ class Sema {
22912291
SourceRange getExprRange(Expr *E) const;
22922292

22932293
ExprResult ActOnIdExpression(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Id,
2294-
bool HasTrailingLParen, bool IsAddressOfOperand);
2294+
bool HasTrailingLParen, bool IsAddressOfOperand,
2295+
CorrectionCandidateCallback *CCC = 0);
22952296

22962297
void DecomposeUnqualifiedId(const UnqualifiedId &Id,
22972298
TemplateArgumentListInfo &Buffer,

clang/lib/Parse/ParseExpr.cpp

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "clang/Sema/DeclSpec.h"
2424
#include "clang/Sema/Scope.h"
2525
#include "clang/Sema/ParsedTemplate.h"
26+
#include "clang/Sema/TypoCorrection.h"
2627
#include "clang/Basic/PrettyStackTrace.h"
2728
#include "RAIIObjectsForParser.h"
2829
#include "llvm/ADT/SmallVector.h"
@@ -174,8 +175,8 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
174175
/// expression: [C99 6.5.17]
175176
/// assignment-expression ...[opt]
176177
/// expression ',' assignment-expression ...[opt]
177-
ExprResult Parser::ParseExpression() {
178-
ExprResult LHS(ParseAssignmentExpression());
178+
ExprResult Parser::ParseExpression(TypeCastState isTypeCast) {
179+
ExprResult LHS(ParseAssignmentExpression(isTypeCast));
179180
return ParseRHSOfBinaryExpression(move(LHS), prec::Comma);
180181
}
181182

@@ -211,7 +212,7 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
211212
}
212213

213214
/// ParseAssignmentExpression - Parse an expr that doesn't include commas.
214-
ExprResult Parser::ParseAssignmentExpression() {
215+
ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) {
215216
if (Tok.is(tok::code_completion)) {
216217
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression);
217218
cutOffParsing();
@@ -221,7 +222,9 @@ ExprResult Parser::ParseAssignmentExpression() {
221222
if (Tok.is(tok::kw_throw))
222223
return ParseThrowExpression();
223224

224-
ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false);
225+
ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false,
226+
/*isAddressOfOperand=*/false,
227+
isTypeCast);
225228
return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment);
226229
}
227230

@@ -417,7 +420,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
417420
///
418421
ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
419422
bool isAddressOfOperand,
420-
bool isTypeCast) {
423+
TypeCastState isTypeCast) {
421424
bool NotCastExpr;
422425
ExprResult Res = ParseCastExpression(isUnaryExpression,
423426
isAddressOfOperand,
@@ -428,6 +431,29 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
428431
return move(Res);
429432
}
430433

434+
namespace {
435+
class CastExpressionIdValidator : public CorrectionCandidateCallback {
436+
public:
437+
CastExpressionIdValidator(bool AllowTypes, bool AllowNonTypes)
438+
: AllowNonTypes(AllowNonTypes) {
439+
WantTypeSpecifiers = AllowTypes;
440+
}
441+
442+
virtual bool ValidateCandidate(const TypoCorrection &candidate) {
443+
NamedDecl *ND = candidate.getCorrectionDecl();
444+
if (!ND)
445+
return candidate.isKeyword();
446+
447+
if (isa<TypeDecl>(ND))
448+
return WantTypeSpecifiers;
449+
return AllowNonTypes;
450+
}
451+
452+
private:
453+
bool AllowNonTypes;
454+
};
455+
}
456+
431457
/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is
432458
/// true, parse a unary-expression. isAddressOfOperand exists because an
433459
/// id-expression that is the operand of address-of gets special treatment
@@ -592,7 +618,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
592618
ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
593619
bool isAddressOfOperand,
594620
bool &NotCastExpr,
595-
bool isTypeCast) {
621+
TypeCastState isTypeCast) {
596622
ExprResult Res;
597623
tok::TokenKind SavedKind = Tok.getKind();
598624
NotCastExpr = false;
@@ -623,7 +649,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
623649
ColonProtectionRAIIObject X(*this, false);
624650

625651
Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
626-
isTypeCast, CastTy, RParenLoc);
652+
isTypeCast == IsTypeCast, CastTy, RParenLoc);
627653
}
628654

629655
switch (ParenExprType) {
@@ -769,9 +795,12 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
769795
// not.
770796
UnqualifiedId Name;
771797
CXXScopeSpec ScopeSpec;
798+
CastExpressionIdValidator Validator(isTypeCast != NotTypeCast,
799+
isTypeCast != IsTypeCast);
772800
Name.setIdentifier(&II, ILoc);
773801
Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, Name,
774-
Tok.is(tok::l_paren), isAddressOfOperand);
802+
Tok.is(tok::l_paren), isAddressOfOperand,
803+
&Validator);
775804
break;
776805
}
777806
case tok::char_constant: // constant: character-constant
@@ -1954,7 +1983,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
19541983
// TODO: For cast expression with CastTy.
19551984
Result = ParseCastExpression(/*isUnaryExpression=*/false,
19561985
/*isAddressOfOperand=*/false,
1957-
/*isTypeCast=*/true);
1986+
/*isTypeCast=*/IsTypeCast);
19581987
if (!Result.isInvalid()) {
19591988
Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc,
19601989
DeclaratorInfo, CastTy,
@@ -1981,7 +2010,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
19812010
} else {
19822011
InMessageExpressionRAIIObject InMessage(*this, false);
19832012

1984-
Result = ParseExpression();
2013+
Result = ParseExpression(MaybeTypeCast);
19852014
ExprType = SimpleExpr;
19862015

19872016
// Don't build a paren expression unless we actually match a ')'.

clang/lib/Parse/ParseExprCXX.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2552,7 +2552,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
25522552
false/*isAddressofOperand*/,
25532553
NotCastExpr,
25542554
// type-id has priority.
2555-
true/*isTypeCast*/);
2555+
IsTypeCast);
25562556
}
25572557

25582558
// If we parsed a cast-expression, it's really a type-id, otherwise it's

clang/lib/Sema/SemaExpr.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1704,7 +1704,8 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
17041704
CXXScopeSpec &SS,
17051705
UnqualifiedId &Id,
17061706
bool HasTrailingLParen,
1707-
bool IsAddressOfOperand) {
1707+
bool IsAddressOfOperand,
1708+
CorrectionCandidateCallback *CCC) {
17081709
assert(!(IsAddressOfOperand && HasTrailingLParen) &&
17091710
"cannot be direct & operand and have a trailing lparen");
17101711

@@ -1819,7 +1820,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
18191820
TemplateArgs);
18201821

18211822
CorrectionCandidateCallback DefaultValidator;
1822-
if (DiagnoseEmptyLookup(S, SS, R, DefaultValidator))
1823+
if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator))
18231824
return ExprError();
18241825

18251826
assert(!R.empty() &&

clang/test/SemaCXX/typo-correction.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,18 @@ struct TestRedecl : public BaseDecl {
114114
};
115115
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'?}}
116116

117+
// Test the improved typo correction for the Parser::ParseCastExpr =>
118+
// Sema::ActOnIdExpression => Sema::DiagnoseEmptyLookup call path.
119+
class SomeNetMessage;
120+
class Message {};
121+
void foo(Message&);
122+
void foo(SomeNetMessage&);
123+
void doit(void *data) {
124+
Message somenetmsg; // expected-note{{'somenetmsg' declared here}}
125+
foo(somenetmessage); // expected-error{{use of undeclared identifier 'somenetmessage'; did you mean 'somenetmsg'?}}
126+
foo((somenetmessage)data); // expected-error{{use of undeclared identifier 'somenetmessage'; did you mean 'SomeNetMessage'?}}
127+
}
128+
117129
// Test the typo-correction callback in BuildRecoveryCallExpr.
118130
// Solves the main issue in PR 9320 of suggesting corrections that take the
119131
// wrong number of arguments.

0 commit comments

Comments
 (0)