arphaman created this revision.

This patch adds a new boolean field to the `DeclRefExpr`, `MemberExpr`, 
`CXXCtorInitializer`, `ObjCIvarRefExpr`, `ObjCPropertyRefExpr` nodes which is 
set to true when these nodes have been produced during typo-correction.

This is useful for Clang-based tooling as it can distinguish between true 
references and the typo-corrected references. The initial tooling support uses 
the flag to prevent token annotation for typo-corrected references and to 
prevent finding typo-corrected references during single TU reference search.


Repository:
  rL LLVM

https://reviews.llvm.org/D38708

Files:
  include/clang/AST/DeclCXX.h
  include/clang/AST/Expr.h
  include/clang/AST/ExprObjC.h
  include/clang/AST/Stmt.h
  lib/AST/DeclCXX.cpp
  lib/AST/Expr.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaExprCXX.cpp
  lib/Sema/SemaExprMember.cpp
  lib/Sema/SemaExprObjC.cpp
  lib/Sema/SemaOverload.cpp
  lib/Sema/SemaPseudoObject.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReader.cpp
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriter.cpp
  lib/Serialization/ASTWriterDecl.cpp
  lib/Serialization/ASTWriterStmt.cpp
  test/Index/typo-annotate-tokens.mm
  test/Index/typo-file-refs.cpp
  test/Index/typo-file-refs.m
  tools/libclang/CIndex.cpp
  tools/libclang/CIndexHigh.cpp
  tools/libclang/CursorVisitor.h

Index: tools/libclang/CursorVisitor.h
===================================================================
--- tools/libclang/CursorVisitor.h
+++ tools/libclang/CursorVisitor.h
@@ -96,6 +96,9 @@
   /// record entries.
   bool VisitDeclsOnly;
 
+  /// \brief Whether we should visit typo-corrected references.
+  bool VisitTypoCorrected = true;
+
   // FIXME: Eventually remove.  This part of a hack to support proper
   // iteration over all Decls contained lexically within an ObjC container.
   DeclContext::decl_iterator *DI_current;
@@ -187,6 +190,8 @@
     return VisitIncludedEntities;
   }
 
+  void setVisitTypoCorrected(bool V = true) { VisitTypoCorrected = V; }
+
   template<typename InputIterator>
   bool visitPreprocessedEntities(InputIterator First, InputIterator Last,
                                  PreprocessingRecord &PPRec,
Index: tools/libclang/CIndexHigh.cpp
===================================================================
--- tools/libclang/CIndexHigh.cpp
+++ tools/libclang/CIndexHigh.cpp
@@ -169,7 +169,9 @@
     if (clang_isExpression(cursor.kind)) {
       if (cursor.kind == CXCursor_DeclRefExpr ||
           cursor.kind == CXCursor_MemberRefExpr) {
-        // continue..
+        // Avoid visiting typo-corrected references.
+        if (cxcursor::getCursorExpr(cursor)->isTypoCorrected())
+          return CXChildVisit_Continue;
 
       } else if (cursor.kind == CXCursor_ObjCMessageExpr &&
                  cxcursor::getSelectorIdentifierIndex(cursor) != -1) {
@@ -228,8 +230,11 @@
                               Visitor);
 
   if (const DeclContext *DC = Dcl->getParentFunctionOrMethod()) {
-    return clang_visitChildren(cxcursor::MakeCXCursor(cast<Decl>(DC), TU),
-                               findFileIdRefVisit, &data);
+    CursorVisitor CursorVis(TU, findFileIdRefVisit, &data,
+                            /*VisitPreprocessorLast=*/false);
+    // Don't include the typo-corrected references.
+    CursorVis.setVisitTypoCorrected(false);
+    return CursorVis.VisitChildren(cxcursor::MakeCXCursor(cast<Decl>(DC), TU));
   }
 
   SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
@@ -239,6 +244,8 @@
                                   /*VisitIncludedEntities=*/false,
                                   Range,
                                   /*VisitDeclsOnly=*/true);
+  // Don't include the typo-corrected references.
+  FindIdRefsVisitor.setVisitTypoCorrected(false);
   return FindIdRefsVisitor.visitFileRegion();
 }
 
Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -847,13 +847,15 @@
       // Visit the initializers in source order
       for (unsigned I = 0, N = WrittenInits.size(); I != N; ++I) {
         CXXCtorInitializer *Init = WrittenInits[I];
-        if (Init->isAnyMemberInitializer()) {
-          if (Visit(MakeCursorMemberRef(Init->getAnyMember(),
-                                        Init->getMemberLocation(), TU)))
-            return true;
-        } else if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo()) {
-          if (Visit(TInfo->getTypeLoc()))
-            return true;
+        if (VisitTypoCorrected | !Init->isTypoCorrected()) {
+          if (Init->isAnyMemberInitializer()) {
+            if (Visit(MakeCursorMemberRef(Init->getAnyMember(),
+                                          Init->getMemberLocation(), TU)))
+              return true;
+          } else if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo()) {
+            if (Visit(TInfo->getTypeLoc()))
+              return true;
+          }
         }
         
         // Visit the initializer value.
@@ -6483,17 +6485,18 @@
 public:
   AnnotateTokensWorker(CXToken *tokens, CXCursor *cursors, unsigned numTokens,
                        CXTranslationUnit TU, SourceRange RegionOfInterest)
-    : Tokens(tokens), Cursors(cursors),
-      NumTokens(numTokens), TokIdx(0), PreprocessingTokIdx(0),
-      AnnotateVis(TU,
-                  AnnotateTokensVisitor, this,
-                  /*VisitPreprocessorLast=*/true,
-                  /*VisitIncludedEntities=*/false,
-                  RegionOfInterest,
-                  /*VisitDeclsOnly=*/false,
-                  AnnotateTokensPostChildrenVisitor),
-      SrcMgr(cxtu::getASTUnit(TU)->getSourceManager()),
-      HasContextSensitiveKeywords(false) { }
+      : Tokens(tokens), Cursors(cursors), NumTokens(numTokens), TokIdx(0),
+        PreprocessingTokIdx(0),
+        AnnotateVis(TU, AnnotateTokensVisitor, this,
+                    /*VisitPreprocessorLast=*/true,
+                    /*VisitIncludedEntities=*/false, RegionOfInterest,
+                    /*VisitDeclsOnly=*/false,
+                    AnnotateTokensPostChildrenVisitor),
+        SrcMgr(cxtu::getASTUnit(TU)->getSourceManager()),
+        HasContextSensitiveKeywords(false) {
+    // Don't annotate typo-corrected references.
+    AnnotateVis.setVisitTypoCorrected(false);
+  }
 
   void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); }
   enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent);
@@ -6720,6 +6723,9 @@
   //  MyCXXClass foo; // Make sure we don't annotate 'foo' as a CallExpr cursor.
   if (clang_isExpression(cursorK) && MoreTokens()) {
     const Expr *E = getCursorExpr(cursor);
+    // Avoid annotating typo-corrected references.
+    if (E->isTypoCorrected())
+      return CXChildVisit_Continue;
     if (const Decl *D = getCursorParentDecl(cursor)) {
       const unsigned I = NextToken();
       if (E->getLocStart().isValid() && D->getLocation().isValid() &&
Index: test/Index/typo-file-refs.m
===================================================================
--- /dev/null
+++ test/Index/typo-file-refs.m
@@ -0,0 +1,76 @@
+struct Structure {
+  int MyCField;
+};
+
+void testMember(struct Structure *x) {
+  x->MyField = 0;
+}
+
+@interface MyInterface
+
+@property int MyProperty;
+
+- (int)MyImplicit;
+- (void)setMyImplicit:(int)x;
+
+@property (class) int MyClassProperty;
+
+- (void)MyMethod;
+
+@end
+
+@implementation MyInterface {
+  int MyIVar;
+}
+
+- (void) method {
+  MyiVar = 0;
+  self->MyiVar = 1;
+
+  self.MyProprty = 0;
+  int x = self.MyProprty;
+
+  int y = self.MyImplict;
+  self.MyImplict = 2;
+
+  MyInterface.MyClassProprty = 0;
+  int z = MyInterface.MyClassProprty;
+
+  [self MyMethd];
+}
+
+@end
+
+// RUN: c-index-test \
+
+// RUN:  -file-refs-at=%s:2:7 \
+// CHECK:      FieldDecl=MyCField:2:7 (Definition)
+// CHECK-NEXT: FieldDecl=MyCField:2:7 (Definition) =[2:7 - 2:15]
+// CHECK-NOT:  MemberRefExpr=MyCField
+
+// RUN:  -file-refs-at=%s:23:7 \
+// CHECK-NEXT: ObjCIvarDecl=MyIVar:23:7 (Definition)
+// CHECK-NEXT: ObjCIvarDecl=MyIVar:23:7 (Definition) =[23:7 - 23:13]
+// CHECK-NOT:  MemberRefExpr=MyIVar
+
+// RUN:  -file-refs-at=%s:11:15 \
+// CHECK-NEXT: ObjCPropertyDecl=MyProperty:11:15
+// CHECK-NEXT: ObjCPropertyDecl=MyProperty:11:15 =[11:15 - 11:25]
+// CHECK-NOT:  MemberRefExpr=MyProperty
+
+// RUN:  -file-refs-at=%s:13:8 \
+// CHECK-NEXT: ObjCInstanceMethodDecl=MyImplicit:13:8
+// CHECK-NEXT: ObjCInstanceMethodDecl=MyImplicit:13:8 =[13:8 - 13:18]
+// CHECK-NOT:  MyImplicit
+
+// RUN:  -file-refs-at=%s:16:23 \
+// CHECK-NEXT: ObjCPropertyDecl=MyClassProperty:16:23 [class,]
+// CHECK-NEXT: ObjCPropertyDecl=MyClassProperty:16:23 [class,] =[16:23 - 16:38]
+// CHECK-NOT:  MyClassProperty
+
+// RUN:  -file-refs-at=%s:18:9 \
+// CHECK-NEXT: ObjCInstanceMethodDecl=MyMethod:18:9
+// CHECK-NEXT: ObjCInstanceMethodDecl=MyMethod:18:9 =[18:9 - 18:17]
+// CHECK-NOT:  MyMethod
+
+// RUN:   %s -fspell-checking | FileCheck %s
Index: test/Index/typo-file-refs.cpp
===================================================================
--- /dev/null
+++ test/Index/typo-file-refs.cpp
@@ -0,0 +1,45 @@
+struct Structure {};
+
+Structure *test555() {
+  Structure *myOwnStringOrig = 0;
+  return myOwnStringNew;
+}
+
+class AClass {
+public:
+  int MyField;
+  void MyMethod();
+
+  void anotherMethod();
+
+  AClass() : MyFild(0) {}
+};
+
+void AClass::anotherMethod() {
+  MYField = 0;
+  MYMethod();
+}
+
+void refMember(AClass *C) {
+  C->MyFild = 1;
+  C->MyMethd();
+}
+
+// RUN: c-index-test \
+
+// RUN:  -file-refs-at=%s:4:14 \
+// CHECK:      VarDecl=myOwnStringOrig:4:14 (Definition)
+// CHECK-NEXT: VarDecl=myOwnStringOrig:4:14 (Definition) =[4:14 - 4:29]
+// CHECK-NOT:  DeclRefExpr=myOwnStringOrig
+
+// RUN:  -file-refs-at=%s:10:7 \
+// CHECK-NEXT: FieldDecl=MyField:10:7 (Definition)
+// CHECK-NEXT: FieldDecl=MyField:10:7 (Definition) =[10:7 - 10:14]
+// CHECK-NOT:  =MyField
+
+// RUN:  -file-refs-at=%s:11:8 \
+// CHECK-NEXT: CXXMethod=MyMethod:11:8
+// CHECK-NEXT: CXXMethod=MyMethod:11:8 =[11:8 - 11:16]
+// CHECK-NOT:  MemberRefExpr=MyMethod
+
+// RUN:   %s -fspell-checking | FileCheck %s
Index: test/Index/typo-annotate-tokens.mm
===================================================================
--- /dev/null
+++ test/Index/typo-annotate-tokens.mm
@@ -0,0 +1,33 @@
+// RUN: c-index-test -test-annotate-tokens=%s:1:1:33:1 %s -fspell-checking | FileCheck %s
+
+struct Structure {};
+
+Structure *test555() {
+  Structure *myOwnStringOrig = 0;
+  return myOwnStringNew; // CHECK: Identifier: "myOwnStringNew" {{\[}}[[@LINE]]:10 - [[@LINE]]:24{{\]}} ReturnStmt=
+}
+
+class AClass {
+public:
+  int MyField;
+  void MyMethod();
+
+  void anotherMethod();
+
+  AClass() : MyFild(0) {} // CHECK: Identifier: "MyFild" {{\[}}[[@LINE]]:14 - [[@LINE]]:20{{\]}} CXXConstructor=AClass
+};
+
+void AClass::anotherMethod() {
+  MYField = 0; // CHECK: Identifier: "MYField" {{\[}}[[@LINE]]:3 - [[@LINE]]:10{{\]}} BinaryOperator=
+  MYMethod();  // CHECK: Identifier: "MYMethod" {{\[}}[[@LINE]]:3 - [[@LINE]]:11{{\]}} CallExpr=MyMethod
+}
+
+@interface MyInterface
+
+@property int MyProperty;
+
+@end
+
+void foo(MyInterface *I) {
+  I.MyProprty = 0; // CHECK: Identifier: "MyProprty" {{\[}}[[@LINE]]:5 - [[@LINE]]:14{{\]}} BinaryOperator=
+}
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -402,6 +402,7 @@
   Record.push_back(E->hasTemplateKWAndArgsInfo());
   Record.push_back(E->hadMultipleCandidates());
   Record.push_back(E->refersToEnclosingVariableOrCapture());
+  Record.push_back(E->isTypoCorrected());
 
   if (E->hasTemplateKWAndArgsInfo()) {
     unsigned NumTemplateArgs = E->getNumTemplateArgs();
@@ -593,6 +594,7 @@
 void ASTStmtWriter::VisitMemberExpr(MemberExpr *E) {
   // Don't call VisitExpr, we'll write everything here.
 
+  Record.push_back(E->isTypoCorrected());
   Record.push_back(E->hasQualifier());
   if (E->hasQualifier())
     Record.AddNestedNameSpecifierLoc(E->getQualifierLoc());
@@ -1030,12 +1032,14 @@
   Record.AddStmt(E->getBase());
   Record.push_back(E->isArrow());
   Record.push_back(E->isFreeIvar());
+  Record.push_back(E->isTypoCorrected());
   Code = serialization::EXPR_OBJC_IVAR_REF_EXPR;
 }
 
 void ASTStmtWriter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
   VisitExpr(E);
   Record.push_back(E->SetterAndMethodRefFlags.getInt());
+  Record.push_back(E->isTypoCorrected());
   Record.push_back(E->isImplicitProperty());
   if (E->isImplicitProperty()) {
     Record.AddDeclRef(E->getImplicitPropertyGetter());
Index: lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- lib/Serialization/ASTWriterDecl.cpp
+++ lib/Serialization/ASTWriterDecl.cpp
@@ -2102,6 +2102,7 @@
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HadMultipleCandidates
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
                            1)); // RefersToEnclosingVariableOrCapture
+  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsTypoCorrected
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclRef
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
   DeclRefExprAbbrev = Stream.EmitAbbrev(std::move(Abv));
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -5882,6 +5882,7 @@
     Writer.push_back(Init->isWritten());
     if (Init->isWritten())
       Writer.push_back(Init->getSourceOrder());
+    Writer.push_back(Init->isTypoCorrected());
   }
 
   return Writer.Emit(serialization::DECL_CXX_CTOR_INITIALIZERS);
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -462,6 +462,7 @@
   E->DeclRefExprBits.HasTemplateKWAndArgsInfo = Record.readInt();
   E->DeclRefExprBits.HadMultipleCandidates = Record.readInt();
   E->DeclRefExprBits.RefersToEnclosingVariableOrCapture = Record.readInt();
+  E->DeclRefExprBits.IsTypoCorrected = Record.readInt();
   unsigned NumTemplateArgs = 0;
   if (E->hasTemplateKWAndArgsInfo())
     NumTemplateArgs = Record.readInt();
@@ -1040,11 +1041,13 @@
   E->setBase(Record.readSubExpr());
   E->setIsArrow(Record.readInt());
   E->setIsFreeIvar(Record.readInt());
+  E->setIsTypoCorrected(Record.readInt());
 }
 
 void ASTStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
   VisitExpr(E);
   unsigned MethodRefFlags = Record.readInt();
+  E->setIsTypoCorrected(Record.readInt());
   bool Implicit = Record.readInt() != 0;
   if (Implicit) {
     ObjCMethodDecl *Getter = ReadDeclAs<ObjCMethodDecl>();
@@ -3232,6 +3235,7 @@
 
       assert(Record.getIdx() == 0);
       NestedNameSpecifierLoc QualifierLoc;
+      bool IsTypoCorrected = Record.readInt();
       if (Record.readInt()) { // HasQualifier.
         QualifierLoc = Record.readNestedNameSpecifierLoc();
       }
@@ -3268,6 +3272,8 @@
                              TemplateKWLoc, MemberD, FoundDecl, MemberNameInfo,
                              HasTemplateKWAndArgsInfo ? &ArgInfo : nullptr, T,
                              VK, OK);
+      if (IsTypoCorrected)
+        cast<MemberExpr>(S)->setIsTypoCorrected();
       Record.readDeclarationNameLoc(cast<MemberExpr>(S)->MemberDNLoc,
                                     MemberD->getDeclName());
       if (HadMultipleCandidates)
Index: lib/Serialization/ASTReader.cpp
===================================================================
--- lib/Serialization/ASTReader.cpp
+++ lib/Serialization/ASTReader.cpp
@@ -8714,6 +8714,8 @@
       unsigned SourceOrder = Record[Idx++];
       BOMInit->setSourceOrder(SourceOrder);
     }
+    if (/*IsTypoCorrected*/ Record[Idx++])
+      Init->setIsTypoCorrected();
 
     CtorInitializers[i] = BOMInit;
   }
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -8896,8 +8896,11 @@
       return ExprError();
   }
 
-  return getDerived().RebuildDeclRefExpr(QualifierLoc, ND, NameInfo,
-                                         TemplateArgs);
+  ExprResult Result =
+      getDerived().RebuildDeclRefExpr(QualifierLoc, ND, NameInfo, TemplateArgs);
+  if (E->isTypoCorrected() && Result.isUsable())
+    Result.getAs<DeclRefExpr>()->setIsTypoCorrected();
+  return Result;
 }
 
 template<typename Derived>
@@ -9325,16 +9328,14 @@
       return ExprError();
   }
 
-  return getDerived().RebuildMemberExpr(Base.get(), FakeOperatorLoc,
-                                        E->isArrow(),
-                                        QualifierLoc,
-                                        TemplateKWLoc,
-                                        MemberNameInfo,
-                                        Member,
-                                        FoundDecl,
-                                        (E->hasExplicitTemplateArgs()
-                                           ? &TransArgs : nullptr),
-                                        FirstQualifierInScope);
+  ExprResult Result = getDerived().RebuildMemberExpr(
+      Base.get(), FakeOperatorLoc, E->isArrow(), QualifierLoc, TemplateKWLoc,
+      MemberNameInfo, Member, FoundDecl,
+      (E->hasExplicitTemplateArgs() ? &TransArgs : nullptr),
+      FirstQualifierInScope);
+  if (E->isTypoCorrected() && Result.isUsable())
+    E->setIsTypoCorrected();
+  return Result;
 }
 
 template<typename Derived>
@@ -11994,9 +11995,12 @@
       Base.get() == E->getBase())
     return E;
 
-  return getDerived().RebuildObjCIvarRefExpr(Base.get(), E->getDecl(),
-                                             E->getLocation(),
-                                             E->isArrow(), E->isFreeIvar());
+  ExprResult Result = getDerived().RebuildObjCIvarRefExpr(
+      Base.get(), E->getDecl(), E->getLocation(), E->isArrow(),
+      E->isFreeIvar());
+  if (E->isTypoCorrected() && Result.isUsable())
+    Result.getAs<ObjCIvarRefExpr>()->setIsTypoCorrected();
+  return Result;
 }
 
 template<typename Derived>
@@ -12019,16 +12023,18 @@
       Base.get() == E->getBase())
     return E;
 
+  ExprResult Result;
   if (E->isExplicitProperty())
-    return getDerived().RebuildObjCPropertyRefExpr(Base.get(),
-                                                   E->getExplicitProperty(),
-                                                   E->getLocation());
-
-  return getDerived().RebuildObjCPropertyRefExpr(Base.get(),
-                                                 SemaRef.Context.PseudoObjectTy,
-                                                 E->getImplicitPropertyGetter(),
-                                                 E->getImplicitPropertySetter(),
-                                                 E->getLocation());
+    Result = getDerived().RebuildObjCPropertyRefExpr(
+        Base.get(), E->getExplicitProperty(), E->getLocation());
+  else
+    Result = getDerived().RebuildObjCPropertyRefExpr(
+        Base.get(), SemaRef.Context.PseudoObjectTy,
+        E->getImplicitPropertyGetter(), E->getImplicitPropertySetter(),
+        E->getLocation());
+  if (E->isTypoCorrected() && Result.isUsable())
+    Result.getAs<ObjCPropertyRefExpr>()->setIsTypoCorrected();
+  return Result;
 }
 
 template<typename Derived>
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4594,6 +4594,8 @@
       AnyErrors = true;
       New->setInvalidDecl();
     } else {
+      if (Init->isTypoCorrected())
+        NewInit.get()->setIsTypoCorrected();
       NewInits.push_back(NewInit.get());
     }
   }
Index: lib/Sema/SemaPseudoObject.cpp
===================================================================
--- lib/Sema/SemaPseudoObject.cpp
+++ lib/Sema/SemaPseudoObject.cpp
@@ -59,17 +59,22 @@
       if (refExpr->isClassReceiver() || refExpr->isSuperReceiver())
         return refExpr;
 
+      ObjCPropertyRefExpr *Result;
       if (refExpr->isExplicitProperty()) {
-        return new (S.Context) ObjCPropertyRefExpr(
+        Result = new (S.Context) ObjCPropertyRefExpr(
             refExpr->getExplicitProperty(), refExpr->getType(),
             refExpr->getValueKind(), refExpr->getObjectKind(),
             refExpr->getLocation(), SpecificCallback(refExpr->getBase(), 0));
+      } else {
+        Result = new (S.Context) ObjCPropertyRefExpr(
+            refExpr->getImplicitPropertyGetter(),
+            refExpr->getImplicitPropertySetter(), refExpr->getType(),
+            refExpr->getValueKind(), refExpr->getObjectKind(),
+            refExpr->getLocation(), SpecificCallback(refExpr->getBase(), 0));
       }
-      return new (S.Context) ObjCPropertyRefExpr(
-          refExpr->getImplicitPropertyGetter(),
-          refExpr->getImplicitPropertySetter(), refExpr->getType(),
-          refExpr->getValueKind(), refExpr->getObjectKind(),
-          refExpr->getLocation(), SpecificCallback(refExpr->getBase(), 0));
+      if (refExpr->isTypoCorrected())
+        Result->setIsTypoCorrected();
+      return Result;
     }
     Expr *rebuildObjCSubscriptRefExpr(ObjCSubscriptRefExpr *refExpr) {
       assert(refExpr->getBaseExpr());
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -11694,6 +11694,8 @@
 
   if (NewFn.isInvalid())
     return ExprError();
+  if (AllowTypoCorrection)
+    NewFn.get()->setIsTypoCorrected();
 
   // This shouldn't cause an infinite loop because we're giving it
   // an expression with viable lookup results, which should never
Index: lib/Sema/SemaExprObjC.cpp
===================================================================
--- lib/Sema/SemaExprObjC.cpp
+++ lib/Sema/SemaExprObjC.cpp
@@ -1903,9 +1903,12 @@
     } else {
       diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest)
                                 << MemberName << QualType(OPT, 0));
-      return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc,
-                                       TypoResult, MemberLoc,
-                                       SuperLoc, SuperType, Super);
+      ExprResult CorrectPRE =
+          HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc, TypoResult, MemberLoc,
+                                    SuperLoc, SuperType, Super);
+      if (CorrectPRE.isUsable())
+        CorrectPRE.get()->setIsTypoCorrected();
+      return CorrectPRE;
     }
   }
   ObjCInterfaceDecl *ClassDeclared;
Index: lib/Sema/SemaExprMember.cpp
===================================================================
--- lib/Sema/SemaExprMember.cpp
+++ lib/Sema/SemaExprMember.cpp
@@ -720,9 +720,12 @@
         for (NamedDecl *ND : TC)
           R.addDecl(ND);
         R.resolveKind();
-        return SemaRef.BuildMemberReferenceExpr(
+        ExprResult CorrectedME = SemaRef.BuildMemberReferenceExpr(
             BaseExpr, BaseExpr->getType(), OpLoc, IsArrow, SS, SourceLocation(),
             nullptr, R, nullptr, nullptr);
+        if (CorrectedME.isUsable())
+          CorrectedME.get()->setIsTypoCorrected();
+        return CorrectedME;
       },
       Sema::CTK_ErrorRecovery, DC);
 
@@ -1364,6 +1367,7 @@
     ObjCInterfaceDecl *ClassDeclared = nullptr;
     ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
 
+    bool IsTypoCorrected = false;
     if (!IV) {
       // Attempt to correct for typos in ivar names.
       auto Validator = llvm::make_unique<DeclFilterCCC<ObjCIvarDecl>>();
@@ -1376,6 +1380,7 @@
             Corrected,
             S.PDiag(diag::err_typecheck_member_reference_ivar_suggest)
                 << IDecl->getDeclName() << MemberName);
+        IsTypoCorrected = true;
 
         // Figure out the class that declares the ivar.
         assert(!ClassDeclared);
@@ -1481,6 +1486,8 @@
       if (!S.Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, MemberLoc))
         S.recordUseOfEvaluatedWeak(Result);
     }
+    if (IsTypoCorrected)
+      Result->setIsTypoCorrected();
 
     return Result;
   }
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -7231,8 +7231,12 @@
     }
   }
 
-  return SemaRef.BuildDeclarationNameExpr(NewSS, R, /*NeedsADL*/ false,
-                                          /*AcceptInvalidDecl*/ true);
+  ExprResult Result =
+      SemaRef.BuildDeclarationNameExpr(NewSS, R, /*NeedsADL*/ false,
+                                       /*AcceptInvalidDecl*/ true);
+  if (Result.isUsable())
+    Result.get()->setIsTypoCorrected();
+  return Result;
 }
 
 namespace {
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -3807,7 +3807,10 @@
           diagnoseTypo(Corr,
                        PDiag(diag::err_mem_init_not_member_or_class_suggest)
                          << MemberOrBase << true);
-          return BuildMemberInitializer(Member, Init, IdLoc);
+          MemInitResult MI = BuildMemberInitializer(Member, Init, IdLoc);
+          if (MI.isUsable())
+            MI.get()->setIsTypoCorrected();
+          return MI;
         } else if (TypeDecl *Type = Corr.getCorrectionDeclAs<TypeDecl>()) {
           const CXXBaseSpecifier *DirectBaseSpec;
           const CXXBaseSpecifier *VirtualBaseSpec;
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -887,6 +887,7 @@
 
   bool SecondTry = false;
   bool IsFilteredTemplateName = false;
+  bool IsTypoCorrected = false;
 
 Corrected:
   switch (Result.getResultKind()) {
@@ -983,9 +984,12 @@
         if (ObjCIvarDecl *Ivar = Result.getAsSingle<ObjCIvarDecl>()) {
           Result.clear();
           ExprResult E(LookupInObjCMethod(Result, S, Ivar->getIdentifier()));
+          if (E.isUsable())
+            E.get()->setIsTypoCorrected();
           return E;
         }
 
+        IsTypoCorrected = true;
         goto Corrected;
       }
     }
@@ -1144,12 +1148,19 @@
     return ParsedType::make(T);
   }
 
-  if (FirstDecl->isCXXClassMember())
-    return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result,
-                                           nullptr, S);
+  if (FirstDecl->isCXXClassMember()) {
+    ExprResult ME = BuildPossibleImplicitMemberExpr(SS, SourceLocation(),
+                                                    Result, nullptr, S);
+    if (IsTypoCorrected && ME.isUsable())
+      ME.get()->setIsTypoCorrected();
+    return ME;
+  }
 
   bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren));
-  return BuildDeclarationNameExpr(SS, Result, ADL);
+  ExprResult DNE = BuildDeclarationNameExpr(SS, Result, ADL);
+  if (IsTypoCorrected && DNE.isUsable())
+    DNE.get()->setIsTypoCorrected();
+  return DNE;
 }
 
 Sema::TemplateNameKindForDiagnostics
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -226,6 +226,29 @@
   llvm_unreachable("unknown expression kind");
 }
 
+bool Expr::isTypoCorrected() const {
+  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(this))
+    return DRE->isTypoCorrected();
+  if (const auto *ME = dyn_cast<MemberExpr>(this))
+    return ME->isTypoCorrected();
+  if (const auto *IVar = dyn_cast<ObjCIvarRefExpr>(this))
+    return IVar->isTypoCorrected();
+  if (const auto *PRef = dyn_cast<ObjCPropertyRefExpr>(this))
+    return PRef->isTypoCorrected();
+  return false;
+}
+
+void Expr::setIsTypoCorrected(bool V) {
+  if (auto *DRE = dyn_cast<DeclRefExpr>(this))
+    DRE->setIsTypoCorrected(V);
+  else if (auto *ME = dyn_cast<MemberExpr>(this))
+    ME->setIsTypoCorrected(V);
+  else if (auto *IVar = dyn_cast<ObjCIvarRefExpr>(this))
+    IVar->setIsTypoCorrected(V);
+  else if (auto *PRef = dyn_cast<ObjCPropertyRefExpr>(this))
+    PRef->setIsTypoCorrected(V);
+}
+
 //===----------------------------------------------------------------------===//
 // Primary Expressions.
 //===----------------------------------------------------------------------===//
@@ -369,6 +392,7 @@
     = (TemplateArgs || TemplateKWLoc.isValid()) ? 1 : 0;
   DeclRefExprBits.RefersToEnclosingVariableOrCapture =
       RefersToEnclosingVariableOrCapture;
+  DeclRefExprBits.IsTypoCorrected = 0;
   if (TemplateArgs) {
     bool Dependent = false;
     bool InstantiationDependent = false;
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp
+++ lib/AST/DeclCXX.cpp
@@ -1946,43 +1946,33 @@
                                        SourceLocation L, Expr *Init,
                                        SourceLocation R,
                                        SourceLocation EllipsisLoc)
-  : Initializee(TInfo), MemberOrEllipsisLocation(EllipsisLoc), Init(Init), 
-    LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(IsVirtual), 
-    IsWritten(false), SourceOrder(0)
-{
-}
+    : Initializee(TInfo), MemberOrEllipsisLocation(EllipsisLoc), Init(Init),
+      LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(IsVirtual),
+      IsWritten(false), SourceOrder(0), IsTypoCorrected(false) {}
 
-CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
-                                       FieldDecl *Member,
+CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, FieldDecl *Member,
                                        SourceLocation MemberLoc,
                                        SourceLocation L, Expr *Init,
                                        SourceLocation R)
-  : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
-    LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false),
-    IsWritten(false), SourceOrder(0)
-{
-}
+    : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
+      LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false),
+      IsWritten(false), SourceOrder(0), IsTypoCorrected(false) {}
 
 CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
                                        IndirectFieldDecl *Member,
                                        SourceLocation MemberLoc,
                                        SourceLocation L, Expr *Init,
                                        SourceLocation R)
-  : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
-    LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false),
-    IsWritten(false), SourceOrder(0)
-{
-}
+    : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
+      LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false),
+      IsWritten(false), SourceOrder(0), IsTypoCorrected(false) {}
 
 CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
-                                       TypeSourceInfo *TInfo,
-                                       SourceLocation L, Expr *Init, 
-                                       SourceLocation R)
-  : Initializee(TInfo), MemberOrEllipsisLocation(), Init(Init),
-    LParenLoc(L), RParenLoc(R), IsDelegating(true), IsVirtual(false),
-    IsWritten(false), SourceOrder(0)
-{
-}
+                                       TypeSourceInfo *TInfo, SourceLocation L,
+                                       Expr *Init, SourceLocation R)
+    : Initializee(TInfo), MemberOrEllipsisLocation(), Init(Init), LParenLoc(L),
+      RParenLoc(R), IsDelegating(true), IsVirtual(false), IsWritten(false),
+      SourceOrder(0), IsTypoCorrected(false) {}
 
 TypeLoc CXXCtorInitializer::getBaseClassLoc() const {
   if (isBaseInitializer())
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -177,6 +177,31 @@
     unsigned HasFoundDecl : 1;
     unsigned HadMultipleCandidates : 1;
     unsigned RefersToEnclosingVariableOrCapture : 1;
+    unsigned IsTypoCorrected : 1;
+  };
+
+  class MemberExprBitfields {
+    friend class MemberExpr;
+    friend class ASTStmtReader;
+    unsigned : NumExprBits;
+
+    unsigned IsTypoCorrected : 1;
+  };
+
+  class ObjCIvarRefExprBitfields {
+    friend class ObjCIvarRefExpr;
+    friend class ASTStmtReader;
+    unsigned : NumExprBits;
+
+    unsigned IsTypoCorrected : 1;
+  };
+
+  class ObjCPropertyRefExprBitfields {
+    friend class ObjCPropertyRefExpr;
+    friend class ASTStmtReader;
+    unsigned : NumExprBits;
+
+    unsigned IsTypoCorrected : 1;
   };
 
   class CastExprBitfields {
@@ -270,6 +295,9 @@
     FloatingLiteralBitfields FloatingLiteralBits;
     UnaryExprOrTypeTraitExprBitfields UnaryExprOrTypeTraitExprBits;
     DeclRefExprBitfields DeclRefExprBits;
+    MemberExprBitfields MemberExprBits;
+    ObjCIvarRefExprBitfields ObjCIvarRefExprBits;
+    ObjCPropertyRefExprBitfields ObjCPropertyRefExprBits;
     CastExprBitfields CastExprBits;
     CallExprBitfields CallExprBits;
     ExprWithCleanupsBitfields ExprWithCleanupsBits;
Index: include/clang/AST/ExprObjC.h
===================================================================
--- include/clang/AST/ExprObjC.h
+++ include/clang/AST/ExprObjC.h
@@ -487,20 +487,23 @@
   bool IsFreeIvar:1;   // True if ivar reference has no base (self assumed).
 
 public:
-  ObjCIvarRefExpr(ObjCIvarDecl *d, QualType t,
-                  SourceLocation l, SourceLocation oploc,
-                  Expr *base,
-                  bool arrow = false, bool freeIvar = false) :
-    Expr(ObjCIvarRefExprClass, t, VK_LValue,
-         d->isBitField() ? OK_BitField : OK_Ordinary,
-         /*TypeDependent=*/false, base->isValueDependent(), 
-         base->isInstantiationDependent(),
-         base->containsUnexpandedParameterPack()), 
-    D(d), Base(base), Loc(l), OpLoc(oploc),
-    IsArrow(arrow), IsFreeIvar(freeIvar) {}
+  ObjCIvarRefExpr(ObjCIvarDecl *d, QualType t, SourceLocation l,
+                  SourceLocation oploc, Expr *base, bool arrow = false,
+                  bool freeIvar = false)
+      : Expr(ObjCIvarRefExprClass, t, VK_LValue,
+             d->isBitField() ? OK_BitField : OK_Ordinary,
+             /*TypeDependent=*/false, base->isValueDependent(),
+             base->isInstantiationDependent(),
+             base->containsUnexpandedParameterPack()),
+        D(d), Base(base), Loc(l), OpLoc(oploc), IsArrow(arrow),
+        IsFreeIvar(freeIvar) {
+    ObjCIvarRefExprBits.IsTypoCorrected = 0;
+  }
 
   explicit ObjCIvarRefExpr(EmptyShell Empty)
-    : Expr(ObjCIvarRefExprClass, Empty) {}
+      : Expr(ObjCIvarRefExprClass, Empty) {
+    ObjCIvarRefExprBits.IsTypoCorrected = 0;
+  }
 
   ObjCIvarDecl *getDecl() { return D; }
   const ObjCIvarDecl *getDecl() const { return D; }
@@ -526,6 +529,13 @@
   SourceLocation getOpLoc() const { return OpLoc; }
   void setOpLoc(SourceLocation L) { OpLoc = L; }
 
+  /// True iff the expression was constructed during typo-correction.
+  bool isTypoCorrected() const { return ObjCIvarRefExprBits.IsTypoCorrected; }
+
+  void setIsTypoCorrected(bool V = true) {
+    ObjCIvarRefExprBits.IsTypoCorrected = V;
+  }
+
   static bool classof(const Stmt *T) {
     return T->getStmtClass() == ObjCIvarRefExprClass;
   }
@@ -580,6 +590,7 @@
       PropertyOrGetter(PD, false), SetterAndMethodRefFlags(),
       IdLoc(l), ReceiverLoc(), Receiver(base) {
     assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject));
+    ObjCPropertyRefExprBits.IsTypoCorrected = 0;
   }
   
   ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t,
@@ -591,6 +602,7 @@
       PropertyOrGetter(PD, false), SetterAndMethodRefFlags(),
       IdLoc(l), ReceiverLoc(sl), Receiver(st.getTypePtr()) {
     assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject));
+    ObjCPropertyRefExprBits.IsTypoCorrected = 0;
   }
 
   ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
@@ -602,6 +614,7 @@
       PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0),
       IdLoc(IdLoc), ReceiverLoc(), Receiver(Base) {
     assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject));
+    ObjCPropertyRefExprBits.IsTypoCorrected = 0;
   }
 
   ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
@@ -612,6 +625,7 @@
       PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0),
       IdLoc(IdLoc), ReceiverLoc(SuperLoc), Receiver(SuperTy.getTypePtr()) {
     assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject));
+    ObjCPropertyRefExprBits.IsTypoCorrected = 0;
   }
 
   ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
@@ -622,10 +636,13 @@
       PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0),
       IdLoc(IdLoc), ReceiverLoc(ReceiverLoc), Receiver(Receiver) {
     assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject));
+    ObjCPropertyRefExprBits.IsTypoCorrected = 0;
   }
 
   explicit ObjCPropertyRefExpr(EmptyShell Empty)
-    : Expr(ObjCPropertyRefExprClass, Empty) {}
+      : Expr(ObjCPropertyRefExprClass, Empty) {
+    ObjCPropertyRefExprBits.IsTypoCorrected = 0;
+  }
 
   bool isImplicitProperty() const { return PropertyOrGetter.getInt(); }
   bool isExplicitProperty() const { return !PropertyOrGetter.getInt(); }
@@ -708,6 +725,15 @@
   }
   SourceLocation getLocEnd() const LLVM_READONLY { return IdLoc; }
 
+  /// True iff the expression was constructed during typo-correction.
+  bool isTypoCorrected() const {
+    return ObjCPropertyRefExprBits.IsTypoCorrected;
+  }
+
+  void setIsTypoCorrected(bool V = true) {
+    ObjCPropertyRefExprBits.IsTypoCorrected = V;
+  }
+
   static bool classof(const Stmt *T) {
     return T->getStmtClass() == ObjCPropertyRefExprClass;
   }
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -850,6 +850,11 @@
     return skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
   }
 
+  /// True iff the expression was constructed during typo-correction.
+  bool isTypoCorrected() const;
+
+  void setIsTypoCorrected(bool V = true);
+
   static bool classof(const Stmt *T) {
     return T->getStmtClass() >= firstExprConstant &&
            T->getStmtClass() <= lastExprConstant;
@@ -1013,6 +1018,7 @@
     DeclRefExprBits.HadMultipleCandidates = 0;
     DeclRefExprBits.RefersToEnclosingVariableOrCapture =
         RefersToEnclosingVariableOrCapture;
+    DeclRefExprBits.IsTypoCorrected = 0;
     computeDependence(D->getASTContext());
   }
 
@@ -1166,6 +1172,13 @@
     return DeclRefExprBits.RefersToEnclosingVariableOrCapture;
   }
 
+  /// True iff the expression was constructed during typo-correction.
+  bool isTypoCorrected() const { return DeclRefExprBits.IsTypoCorrected; }
+
+  void setIsTypoCorrected(bool V = true) {
+    DeclRefExprBits.IsTypoCorrected = V;
+  }
+
   static bool classof(const Stmt *T) {
     return T->getStmtClass() == DeclRefExprClass;
   }
@@ -2447,6 +2460,7 @@
         IsArrow(isarrow), HasQualifierOrFoundDecl(false),
         HasTemplateKWAndArgsInfo(false), HadMultipleCandidates(false) {
     assert(memberdecl->getDeclName() == NameInfo.getName());
+    MemberExprBits.IsTypoCorrected = 0;
   }
 
   // NOTE: this constructor should be used only when it is known that
@@ -2462,7 +2476,9 @@
         Base(base), MemberDecl(memberdecl), MemberDNLoc(), MemberLoc(l),
         OperatorLoc(operatorloc), IsArrow(isarrow),
         HasQualifierOrFoundDecl(false), HasTemplateKWAndArgsInfo(false),
-        HadMultipleCandidates(false) {}
+        HadMultipleCandidates(false) {
+    MemberExprBits.IsTypoCorrected = 0;
+  }
 
   static MemberExpr *Create(const ASTContext &C, Expr *base, bool isarrow,
                             SourceLocation OperatorLoc,
@@ -2617,6 +2633,11 @@
     return LO.AppleKext || !hasQualifier();
   }
 
+  /// True iff the expression was constructed during typo-correction.
+  bool isTypoCorrected() const { return MemberExprBits.IsTypoCorrected; }
+
+  void setIsTypoCorrected(bool V = true) { MemberExprBits.IsTypoCorrected = V; }
+
   static bool classof(const Stmt *T) {
     return T->getStmtClass() == MemberExprClass;
   }
Index: include/clang/AST/DeclCXX.h
===================================================================
--- include/clang/AST/DeclCXX.h
+++ include/clang/AST/DeclCXX.h
@@ -2158,6 +2158,9 @@
   /// of this initializer in the original sources, counting from 0.
   unsigned SourceOrder : 13;
 
+  /// Whether this initializer was typo-corrected.
+  unsigned IsTypoCorrected : 1;
+
 public:
   /// \brief Creates a new base-class initializer.
   explicit
@@ -2312,6 +2315,11 @@
 
   /// \brief Get the initializer.
   Expr *getInit() const { return static_cast<Expr*>(Init); }
+
+  /// True iff the initializer was constructed during typo-correction.
+  bool isTypoCorrected() const { return IsTypoCorrected; }
+
+  void setIsTypoCorrected(bool V = true) { IsTypoCorrected = V; }
 };
 
 /// Description of a constructor that was inherited from a base class.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D38708: [AST] Flag the... Alex Lorenz via Phabricator via cfe-commits

Reply via email to