[cfe-commits] PATCH: Avoid correcting unknown identifiers to types where types aren't allowed. (issue 5572049)
rikka at google.com
rikka at google.com
Mon Jan 23 12:45:59 PST 2012
Reviewers: kyrtzidis_apple.com,
Description:
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.
Please review this at http://codereview.appspot.com/5572049/
Affected files:
M include/clang/Parse/Parser.h
M include/clang/Sema/Sema.h
M lib/Parse/ParseExpr.cpp
M lib/Parse/ParseExprCXX.cpp
M lib/Sema/SemaExpr.cpp
M test/SemaCXX/typo-correction.cpp
-------------- next part --------------
Index: include/clang/Parse/Parser.h
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index ea79b987e1b48d6197f6d7e9685518ae461d06c3..07f39603f00648d7995e8b803c17370f8ff62026 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -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.
Index: include/clang/Sema/Sema.h
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 2055f3bf6ac17a8cdde5fe87b8253452cc426003..238e5ae3e7f404fe6e78dee53f095419e4341f1b 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -2287,7 +2287,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,
Index: lib/Parse/ParseExpr.cpp
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index bdebb5e6b9492a06859b0383606d1728390fd2e5..c3c5e2611836607e62bdc035740dbc167b9c7d73 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -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
@@ -1953,7 +1982,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,
@@ -1980,7 +2009,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 ')'.
Index: lib/Parse/ParseExprCXX.cpp
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 8046f6b88c7a69d58069562b112d2ec44657e162..cc01d291cde3d85ac75eb708280ea5d35edabaf9 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -2549,7 +2549,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
Index: lib/Sema/SemaExpr.cpp
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 96496662503c33437e10db34b0c157b6927e1f5d..af3ac8057676d8d38fc27c57fc82f75fbff7b6ef 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1696,7 +1696,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");
@@ -1811,7 +1812,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() &&
Index: test/SemaCXX/typo-correction.cpp
diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp
index 56417cd87dc5949cf3d0643c0d720b8dbb0de592..1fd10ac75987a4a08142d2465299387c33624fe1 100644
--- a/test/SemaCXX/typo-correction.cpp
+++ b/test/SemaCXX/typo-correction.cpp
@@ -113,3 +113,15 @@ struct TestRedecl : public BaseDecl {
void add_it(int i); // expected-note{{'add_it' declared here}}
};
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'?}}
+}
More information about the cfe-commits
mailing list