]> granicus.if.org Git - clang/commitdiff
[SemaObjC] Improve ObjCDictionaryLiteral and ObjCArryLiteral diagnostics
authorBruno Cardoso Lopes <bruno.cardoso@gmail.com>
Tue, 19 Jul 2016 20:21:18 +0000 (20:21 +0000)
committerBruno Cardoso Lopes <bruno.cardoso@gmail.com>
Tue, 19 Jul 2016 20:21:18 +0000 (20:21 +0000)
Sema actions on ObjCDictionaryLiteral and ObjCArryLiteral are currently
done as a side-effect of Sema upon parent expressions, which incurs of
delayed typo corrections for such literals to be performed by TypoTransforms
upon the ObjCDictionaryLiteral and ObjCArryLiteral themselves instead of
its elements individually.

This is specially bad because it was not designed to act on several
elements; searching through all possible combinations of corrections for
several elements is very expensive. Additionally, when one of the
elements has no correction candidate, we still explore all options and
at the end emit no typo corrections whatsoever.

Do the proper sema actions by acting on each element alone during appropriate
literal parsing time to get proper diagonistics and decent compile time
behavior.

Differential Revision: http://reviews.llvm.org/D22183

rdar://problem/21046678

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@276020 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Parse/ParseObjc.cpp
test/SemaObjC/objc-array-literal.m
test/SemaObjC/objc-dictionary-literal.m

index 67abe5839bfef0e3309664c252cf709323a02169..75ddfcb03ed4bb7bc7e28b70bcb5cd3ed1fecca3 100644 (file)
@@ -3416,6 +3416,7 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
   ExprVector ElementExprs;                   // array elements.
   ConsumeBracket(); // consume the l_square.
 
+  bool HasInvalidEltExpr = false;
   while (Tok.isNot(tok::r_square)) {
     // Parse list of array element expressions (all must be id types).
     ExprResult Res(ParseAssignmentExpression());
@@ -3427,11 +3428,15 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
       return Res;
     }    
     
+    Res = Actions.CorrectDelayedTyposInExpr(Res.get());
+    if (Res.isInvalid())
+      HasInvalidEltExpr = true;
+
     // Parse the ellipsis that indicates a pack expansion.
     if (Tok.is(tok::ellipsis))
       Res = Actions.ActOnPackExpansion(Res.get(), ConsumeToken());    
     if (Res.isInvalid())
-      return true;
+      HasInvalidEltExpr = true;
 
     ElementExprs.push_back(Res.get());
 
@@ -3442,6 +3447,10 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
                                                             << tok::comma);
   }
   SourceLocation EndLoc = ConsumeBracket(); // location of ']'
+
+  if (HasInvalidEltExpr)
+    return ExprError();
+
   MultiExprArg Args(ElementExprs);
   return Actions.BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args);
 }
@@ -3449,6 +3458,7 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
 ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
   SmallVector<ObjCDictionaryElement, 4> Elements; // dictionary elements.
   ConsumeBrace(); // consume the l_square.
+  bool HasInvalidEltExpr = false;
   while (Tok.isNot(tok::r_brace)) {
     // Parse the comma separated key : value expressions.
     ExprResult KeyExpr;
@@ -3478,7 +3488,15 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
       return ValueExpr;
     }
     
-    // Parse the ellipsis that designates this as a pack expansion.
+    // Check the key and value for possible typos
+    KeyExpr = Actions.CorrectDelayedTyposInExpr(KeyExpr.get());
+    ValueExpr = Actions.CorrectDelayedTyposInExpr(ValueExpr.get());
+    if (KeyExpr.isInvalid() || ValueExpr.isInvalid())
+      HasInvalidEltExpr = true;
+
+    // Parse the ellipsis that designates this as a pack expansion. Do not
+    // ActOnPackExpansion here, leave it to template instantiation time where
+    // we can get better diagnostics.
     SourceLocation EllipsisLoc;
     if (getLangOpts().CPlusPlus)
       TryConsumeToken(tok::ellipsis, EllipsisLoc);
@@ -3495,6 +3513,9 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
                                                             << tok::comma);
   }
   SourceLocation EndLoc = ConsumeBrace();
+
+  if (HasInvalidEltExpr)
+    return ExprError();
   
   // Create the ObjCDictionaryLiteral.
   return Actions.BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc),
index 281994a758b2773b1cbedd45509f507224c400c0..c0a0c67d442dddfcacbccb08bf3fb66e3d3760a7 100644 (file)
@@ -67,3 +67,11 @@ id radar15147688() {
   x = @[ @"stuff", @"hello" "world"]; // expected-warning {{concatenated NSString literal for an NSArray expression}}
   return x;
 }
+
+enum XXXYYYZZZType { XXXYYYZZZTypeAny }; // expected-note {{'XXXYYYZZZTypeAny' declared here}}
+void foo() {
+  NSArray *array = @[
+    @(XXXYYYZZZTypeA),                 // expected-error {{use of undeclared identifier 'XXXYYYZZZTypeA'; did you mean 'XXXYYYZZZTypeAny'}}
+    @(XXXYYYZZZTypeSomethingSomething) // expected-error {{use of undeclared identifier 'XXXYYYZZZTypeSomethingSomething'}}
+  ];
+}
index 1a2c29f74db0423c1d31ef20ad0278436b761ebb..ce301a0c73afffbeb79c8397e85c32ffa46520f4 100644 (file)
@@ -63,3 +63,10 @@ int main() {
        return 0;
 }
 
+enum XXXYYYZZZType { XXXYYYZZZTypeAny }; // expected-note {{'XXXYYYZZZTypeAny' declared here}}
+void foo() {
+  NSDictionary *d = @{
+    @"A" : @(XXXYYYZZZTypeA), // expected-error {{use of undeclared identifier 'XXXYYYZZZTypeA'; did you mean 'XXXYYYZZZTypeAny'}}
+    @"F" : @(XXXYYYZZZTypeSomethingSomething), // expected-error {{use of undeclared identifier 'XXXYYYZZZTypeSomethingSomething'}}
+  };
+}