<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        margin-bottom:.0001pt;
        font-size:12.0pt;
        font-family:"Times New Roman",serif;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
p.msonormal0, li.msonormal0, div.msonormal0
        {mso-style-name:msonormal;
        mso-margin-top-alt:auto;
        margin-right:0in;
        mso-margin-bottom-alt:auto;
        margin-left:0in;
        font-size:12.0pt;
        font-family:"Times New Roman",serif;}
span.EmailStyle18
        {mso-style-type:personal-reply;
        font-family:"Calibri",sans-serif;
        color:#1F497D;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-family:"Calibri",sans-serif;}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="EN-US" link="blue" vlink="purple">
<div class="WordSection1">
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif;color:#1F497D">Hi, I think this test is still broken on Windows when you are building a cross compiler as we at Sony do. I have put the details in PR40033. Can somebody take
 a look?<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif;color:#1F497D"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif;color:#1F497D">Douglas Yung<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Calibri",sans-serif;color:#1F497D"><o:p> </o:p></span></p>
<p class="MsoNormal"><b><span style="font-size:11.0pt;font-family:"Calibri",sans-serif">From:</span></b><span style="font-size:11.0pt;font-family:"Calibri",sans-serif"> cfe-commits <cfe-commits-bounces@lists.llvm.org>
<b>On Behalf Of </b>Reid Kleckner via cfe-commits<br>
<b>Sent:</b> Thursday, December 13, 2018 13:51<br>
<b>To:</b> Ilya Biryukov <ibiryukov@google.com><br>
<b>Cc:</b> cfe-commits <cfe-commits@lists.llvm.org><br>
<b>Subject:</b> Re: r349053 - [CodeComplete] Fill preferred type on binary expressions<o:p></o:p></span></p>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<div>
<p class="MsoNormal">r349086 should take care of it, but you may want to tweak it.<o:p></o:p></p>
</div>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<div>
<p class="MsoNormal">On Thu, Dec 13, 2018 at 1:30 PM Reid Kleckner <<a href="mailto:rnk@google.com">rnk@google.com</a>> wrote:<o:p></o:p></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in">
<div>
<div>
<p class="MsoNormal">This new test doesn't pass on Windows. I think it's an LLP64-ness bug based on the output:<o:p></o:p></p>
<div>
<div>
<p class="MsoNormal">Note: Google Test filter = PreferredTypeTest.Binar*<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">[==========] Running 1 test from 1 test case.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">[----------] Global test environment set-up.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">[----------] 1 test from PreferredTypeTest<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">[ RUN      ] PreferredTypeTest.BinaryExpr<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">test.cc:4:45: error: invalid operands to binary expression ('float' and 'int')<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">      x += 10; x -= 10; x *= 10; x /= 10; x %= 10;<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">                                          ~ ^  ~~<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">1 error generated.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">test.cc:4:45: error: invalid operands to binary expression ('float' and 'int')<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">      x += 10; x -= 10; x *= 10; x /= 10; x %= 10;<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">                                          ~ ^  ~~<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">1 error generated.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">test.cc:4:45: error: invalid operands to binary expression ('float' and 'int')<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">      x += 10; x -= 10; x *= 10; x /= 10; x %= 10;<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">                                          ~ ^  ~~<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">1 error generated.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">test.cc:4:45: error: invalid operands to binary expression ('float' and 'int')<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">      x += 10; x -= 10; x *= 10; x /= 10; x %= 10;<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">                                          ~ ^  ~~<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">1 error generated.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">test.cc:4:45: error: invalid operands to binary expression ('float' and 'int')<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">      x += 10; x -= 10; x *= 10; x /= 10; x %= 10;<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">                                          ~ ^  ~~<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">1 error generated.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">C:\src\llvm-project\clang\unittests\Sema\CodeCompleteTest.cpp(216): error: Value of: collectPreferredTypes(Code)<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">Expected: only contains elements that is equal to "long"<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">  Actual: { "long long", "long long", "long long" }, whose element #0 doesn't match<o:p></o:p></p>
</div>
</div>
</div>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<div>
<p class="MsoNormal">On Thu, Dec 13, 2018 at 8:09 AM Ilya Biryukov via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>> wrote:<o:p></o:p></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in">
<p class="MsoNormal">Author: ibiryukov<br>
Date: Thu Dec 13 08:06:11 2018<br>
New Revision: 349053<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=349053&view=rev" target="_blank">
http://llvm.org/viewvc/llvm-project?rev=349053&view=rev</a><br>
Log:<br>
[CodeComplete] Fill preferred type on binary expressions<br>
<br>
Reviewers: kadircet<br>
<br>
Reviewed By: kadircet<br>
<br>
Subscribers: arphaman, cfe-commits<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D55648" target="_blank">
https://reviews.llvm.org/D55648</a><br>
<br>
Modified:<br>
    cfe/trunk/include/clang/Sema/Sema.h<br>
    cfe/trunk/lib/Parse/ParseExpr.cpp<br>
    cfe/trunk/lib/Sema/SemaCodeComplete.cpp<br>
    cfe/trunk/test/Index/complete-exprs.c<br>
    cfe/trunk/unittests/Sema/CodeCompleteTest.cpp<br>
<br>
Modified: cfe/trunk/include/clang/Sema/Sema.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=349053&r1=349052&r2=349053&view=diff" target="_blank">
http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=349053&r1=349052&r2=349053&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Sema/Sema.h (original)<br>
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Dec 13 08:06:11 2018<br>
@@ -10350,7 +10350,7 @@ public:<br>
   void CodeCompleteInitializer(Scope *S, Decl *D);<br>
   void CodeCompleteReturn(Scope *S);<br>
   void CodeCompleteAfterIf(Scope *S);<br>
-  void CodeCompleteAssignmentRHS(Scope *S, Expr *LHS);<br>
+  void CodeCompleteBinaryRHS(Scope *S, Expr *LHS, tok::TokenKind Op);<br>
<br>
   void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,<br>
                                bool EnteringContext, QualType BaseType);<br>
<br>
Modified: cfe/trunk/lib/Parse/ParseExpr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=349053&r1=349052&r2=349053&view=diff" target="_blank">
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=349053&r1=349052&r2=349053&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)<br>
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Thu Dec 13 08:06:11 2018<br>
@@ -393,10 +393,11 @@ Parser::ParseRHSOfBinaryExpression(ExprR<br>
       }<br>
     }<br>
<br>
-    // Code completion for the right-hand side of an assignment expression<br>
-    // goes through a special hook that takes the left-hand side into account.<br>
-    if (Tok.is(tok::code_completion) && NextTokPrec == prec::Assignment) {<br>
-      Actions.CodeCompleteAssignmentRHS(getCurScope(), LHS.get());<br>
+    // Code completion for the right-hand side of a binary expression goes<br>
+    // through a special hook that takes the left-hand side into account.<br>
+    if (Tok.is(tok::code_completion)) {<br>
+      Actions.CodeCompleteBinaryRHS(getCurScope(), LHS.get(),<br>
+                                    OpToken.getKind());<br>
       cutOffParsing();<br>
       return ExprError();<br>
     }<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=349053&r1=349052&r2=349053&view=diff" target="_blank">
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=349053&r1=349052&r2=349053&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Thu Dec 13 08:06:11 2018<br>
@@ -4878,9 +4878,86 @@ void Sema::CodeCompleteAfterIf(Scope *S)<br>
                             Results.data(), Results.size());<br>
 }<br>
<br>
-void Sema::CodeCompleteAssignmentRHS(Scope *S, Expr *LHS) {<br>
-  if (LHS)<br>
-    CodeCompleteExpression(S, static_cast<Expr *>(LHS)->getType());<br>
+static QualType getPreferredTypeOfBinaryRHS(Sema &S, Expr *LHS,<br>
+                                            tok::TokenKind Op) {<br>
+  if (!LHS)<br>
+    return QualType();<br>
+<br>
+  QualType LHSType = LHS->getType();<br>
+  if (LHSType->isPointerType()) {<br>
+    if (Op == tok::plus || Op == tok::plusequal || Op == tok::minusequal)<br>
+      return S.getASTContext().getPointerDiffType();<br>
+    // Pointer difference is more common than subtracting an int from a pointer.<br>
+    if (Op == tok::minus)<br>
+      return LHSType;<br>
+  }<br>
+<br>
+  switch (Op) {<br>
+  // No way to infer the type of RHS from LHS.<br>
+  case tok::comma:<br>
+    return QualType();<br>
+  // Prefer the type of the left operand for all of these.<br>
+  // Arithmetic operations.<br>
+  case tok::plus:<br>
+  case tok::plusequal:<br>
+  case tok::minus:<br>
+  case tok::minusequal:<br>
+  case tok::percent:<br>
+  case tok::percentequal:<br>
+  case tok::slash:<br>
+  case tok::slashequal:<br>
+  case tok::star:<br>
+  case tok::starequal:<br>
+  // Assignment.<br>
+  case tok::equal:<br>
+  // Comparison operators.<br>
+  case tok::equalequal:<br>
+  case tok::exclaimequal:<br>
+  case tok::less:<br>
+  case tok::lessequal:<br>
+  case tok::greater:<br>
+  case tok::greaterequal:<br>
+  case tok::spaceship:<br>
+    return LHS->getType();<br>
+  // Binary shifts are often overloaded, so don't try to guess those.<br>
+  case tok::greatergreater:<br>
+  case tok::greatergreaterequal:<br>
+  case tok::lessless:<br>
+  case tok::lesslessequal:<br>
+    if (LHSType->isIntegralOrEnumerationType())<br>
+      return S.getASTContext().IntTy;<br>
+    return QualType();<br>
+  // Logical operators, assume we want bool.<br>
+  case tok::ampamp:<br>
+  case tok::pipepipe:<br>
+  case tok::caretcaret:<br>
+    return S.getASTContext().BoolTy;<br>
+  // Operators often used for bit manipulation are typically used with the type<br>
+  // of the left argument.<br>
+  case tok::pipe:<br>
+  case tok::pipeequal:<br>
+  case tok::caret:<br>
+  case tok::caretequal:<br>
+  case tok::amp:<br>
+  case tok::ampequal:<br>
+    if (LHSType->isIntegralOrEnumerationType())<br>
+      return LHSType;<br>
+    return QualType();<br>
+  // RHS should be a pointer to a member of the 'LHS' type, but we can't give<br>
+  // any particular type here.<br>
+  case tok::periodstar:<br>
+  case tok::arrowstar:<br>
+    return QualType();<br>
+  default:<br>
+    assert(false && "unhandled binary op");<br>
+    return QualType();<br>
+  }<br>
+}<br>
+<br>
+void Sema::CodeCompleteBinaryRHS(Scope *S, Expr *LHS, tok::TokenKind Op) {<br>
+  auto PreferredType = getPreferredTypeOfBinaryRHS(*this, LHS, Op);<br>
+  if (!PreferredType.isNull())<br>
+    CodeCompleteExpression(S, PreferredType);<br>
   else<br>
     CodeCompleteOrdinaryName(S, PCC_Expression);<br>
 }<br>
<br>
Modified: cfe/trunk/test/Index/complete-exprs.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-exprs.c?rev=349053&r1=349052&r2=349053&view=diff" target="_blank">
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-exprs.c?rev=349053&r1=349052&r2=349053&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/Index/complete-exprs.c (original)<br>
+++ cfe/trunk/test/Index/complete-exprs.c Thu Dec 13 08:06:11 2018<br>
@@ -33,16 +33,11 @@ void f5(float f) {<br>
 // CHECK-CC1: ParmDecl:{ResultType int}{TypedText j} (8)<br>
 // CHECK-CC1: NotImplemented:{ResultType size_t}{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)<br>
 // RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:10 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s<br>
-// RUN: c-index-test -code-completion-at=%s:7:14 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s<br>
-// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:14 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s<br>
-// CHECK-CC3: macro definition:{TypedText __VERSION__} (70)<br>
-// CHECK-CC3: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (50)<br>
-// CHECK-CC3-NOT: NotImplemented:{TypedText float}<br>
-// CHECK-CC3: ParmDecl:{ResultType int}{TypedText j} (34)<br>
-// CHECK-CC3: NotImplemented:{ResultType size_t}{TypedText sizeof}{LeftParen (}{Placeholder expressio<br>
+// RUN: c-index-test -code-completion-at=%s:7:14 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s<br>
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:14 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s<br>
<br>
-// RUN: c-index-test -code-completion-at=%s:7:18 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s<br>
-// RUN: c-index-test -code-completion-at=%s:7:22 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s<br>
+// RUN: c-index-test -code-completion-at=%s:7:18 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s<br>
+// RUN: c-index-test -code-completion-at=%s:7:22 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s<br>
 // RUN: c-index-test -code-completion-at=%s:7:2 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC2 %s<br>
 // CHECK-CC2: macro definition:{TypedText __VERSION__} (70)<br>
 // CHECK-CC2: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (50)<br>
<br>
Modified: cfe/trunk/unittests/Sema/CodeCompleteTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Sema/CodeCompleteTest.cpp?rev=349053&r1=349052&r2=349053&view=diff" target="_blank">
http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Sema/CodeCompleteTest.cpp?rev=349053&r1=349052&r2=349053&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/unittests/Sema/CodeCompleteTest.cpp (original)<br>
+++ cfe/trunk/unittests/Sema/CodeCompleteTest.cpp Thu Dec 13 08:06:11 2018<br>
@@ -14,31 +14,39 @@<br>
 #include "clang/Sema/Sema.h"<br>
 #include "clang/Sema/SemaDiagnostic.h"<br>
 #include "clang/Tooling/Tooling.h"<br>
-#include "gtest/gtest.h"<br>
 #include "gmock/gmock.h"<br>
+#include "gtest/gtest.h"<br>
+#include <cstddef><br>
+#include <string><br>
<br>
 namespace {<br>
<br>
 using namespace clang;<br>
 using namespace clang::tooling;<br>
+using ::testing::Each;<br>
 using ::testing::UnorderedElementsAre;<br>
<br>
 const char TestCCName[] = "test.cc";<br>
-using VisitedContextResults = std::vector<std::string>;<br>
<br>
-class VisitedContextFinder: public CodeCompleteConsumer {<br>
+struct CompletionContext {<br>
+  std::vector<std::string> VisitedNamespaces;<br>
+  std::string PreferredType;<br>
+};<br>
+<br>
+class VisitedContextFinder : public CodeCompleteConsumer {<br>
 public:<br>
-  VisitedContextFinder(VisitedContextResults &Results)<br>
+  VisitedContextFinder(CompletionContext &ResultCtx)<br>
       : CodeCompleteConsumer(/*CodeCompleteOpts=*/{},<br>
                              /*CodeCompleteConsumer*/ false),<br>
-        VCResults(Results),<br>
+        ResultCtx(ResultCtx),<br>
         CCTUInfo(std::make_shared<GlobalCodeCompletionAllocator>()) {}<br>
<br>
   void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,<br>
                                   CodeCompletionResult *Results,<br>
                                   unsigned NumResults) override {<br>
-    VisitedContexts = Context.getVisitedContexts();<br>
-    VCResults = getVisitedNamespace();<br>
+    ResultCtx.VisitedNamespaces =<br>
+        getVisitedNamespace(Context.getVisitedContexts());<br>
+    ResultCtx.PreferredType = Context.getPreferredType().getAsString();<br>
   }<br>
<br>
   CodeCompletionAllocator &getAllocator() override {<br>
@@ -47,7 +55,9 @@ public:<br>
<br>
   CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }<br>
<br>
-  std::vector<std::string> getVisitedNamespace() const {<br>
+private:<br>
+  std::vector<std::string> getVisitedNamespace(<br>
+      CodeCompletionContext::VisitedContextSet VisitedContexts) const {<br>
     std::vector<std::string> NSNames;<br>
     for (const auto *Context : VisitedContexts)<br>
       if (const auto *NS = llvm::dyn_cast<NamespaceDecl>(Context))<br>
@@ -55,27 +65,25 @@ public:<br>
     return NSNames;<br>
   }<br>
<br>
-private:<br>
-  VisitedContextResults& VCResults;<br>
+  CompletionContext &ResultCtx;<br>
   CodeCompletionTUInfo CCTUInfo;<br>
-  CodeCompletionContext::VisitedContextSet VisitedContexts;<br>
 };<br>
<br>
 class CodeCompleteAction : public SyntaxOnlyAction {<br>
 public:<br>
-  CodeCompleteAction(ParsedSourceLocation P, VisitedContextResults &Results)<br>
-      : CompletePosition(std::move(P)), VCResults(Results) {}<br>
+  CodeCompleteAction(ParsedSourceLocation P, CompletionContext &ResultCtx)<br>
+      : CompletePosition(std::move(P)), ResultCtx(ResultCtx) {}<br>
<br>
   bool BeginInvocation(CompilerInstance &CI) override {<br>
     CI.getFrontendOpts().CodeCompletionAt = CompletePosition;<br>
-    CI.setCodeCompletionConsumer(new VisitedContextFinder(VCResults));<br>
+    CI.setCodeCompletionConsumer(new VisitedContextFinder(ResultCtx));<br>
     return true;<br>
   }<br>
<br>
 private:<br>
   // 1-based code complete position <Line, Col>;<br>
   ParsedSourceLocation CompletePosition;<br>
-  VisitedContextResults& VCResults;<br>
+  CompletionContext &ResultCtx;<br>
 };<br>
<br>
 ParsedSourceLocation offsetToPosition(llvm::StringRef Code, size_t Offset) {<br>
@@ -88,21 +96,49 @@ ParsedSourceLocation offsetToPosition(ll<br>
           static_cast<unsigned>(Offset - StartOfLine + 1)};<br>
 }<br>
<br>
-VisitedContextResults runCodeCompleteOnCode(StringRef Code) {<br>
-  VisitedContextResults Results;<br>
-  auto TokenOffset = Code.find('^');<br>
-  assert(TokenOffset != StringRef::npos &&<br>
-         "Completion token ^ wasn't found in Code.");<br>
-  std::string WithoutToken = Code.take_front(TokenOffset);<br>
-  WithoutToken += Code.drop_front(WithoutToken.size() + 1);<br>
-  assert(StringRef(WithoutToken).find('^') == StringRef::npos &&<br>
-         "expected exactly one completion token ^ inside the code");<br>
-<br>
+CompletionContext runCompletion(StringRef Code, size_t Offset) {<br>
+  CompletionContext ResultCtx;<br>
   auto Action = llvm::make_unique<CodeCompleteAction>(<br>
-      offsetToPosition(WithoutToken, TokenOffset), Results);<br>
+      offsetToPosition(Code, Offset), ResultCtx);<br>
   clang::tooling::runToolOnCodeWithArgs(Action.release(), Code, {"-std=c++11"},<br>
                                         TestCCName);<br>
-  return Results;<br>
+  return ResultCtx;<br>
+}<br>
+<br>
+struct ParsedAnnotations {<br>
+  std::vector<size_t> Points;<br>
+  std::string Code;<br>
+};<br>
+<br>
+ParsedAnnotations parseAnnotations(StringRef AnnotatedCode) {<br>
+  ParsedAnnotations R;<br>
+  while (!AnnotatedCode.empty()) {<br>
+    size_t NextPoint = AnnotatedCode.find('^');<br>
+    if (NextPoint == StringRef::npos) {<br>
+      R.Code += AnnotatedCode;<br>
+      AnnotatedCode = "";<br>
+      break;<br>
+    }<br>
+    R.Code += AnnotatedCode.substr(0, NextPoint);<br>
+    R.Points.push_back(R.Code.size());<br>
+<br>
+    AnnotatedCode = AnnotatedCode.substr(NextPoint + 1);<br>
+  }<br>
+  return R;<br>
+}<br>
+<br>
+CompletionContext runCodeCompleteOnCode(StringRef AnnotatedCode) {<br>
+  ParsedAnnotations P = parseAnnotations(AnnotatedCode);<br>
+  assert(P.Points.size() == 1 && "expected exactly one annotation point");<br>
+  return runCompletion(P.Code, P.Points.front());<br>
+}<br>
+<br>
+std::vector<std::string> collectPreferredTypes(StringRef AnnotatedCode) {<br>
+  ParsedAnnotations P = parseAnnotations(AnnotatedCode);<br>
+  std::vector<std::string> Types;<br>
+  for (size_t Point : P.Points)<br>
+    Types.push_back(runCompletion(P.Code, Point).PreferredType);<br>
+  return Types;<br>
 }<br>
<br>
 TEST(SemaCodeCompleteTest, VisitedNSForValidQualifiedId) {<br>
@@ -119,7 +155,8 @@ TEST(SemaCodeCompleteTest, VisitedNSForV<br>
      inline namespace bar { using namespace ns3::nns3; }<br>
      } // foo<br>
      namespace ns { foo::^ }<br>
-  )cpp");<br>
+  )cpp")<br>
+                       .VisitedNamespaces;<br>
   EXPECT_THAT(VisitedNS, UnorderedElementsAre("foo", "ns1", "ns2", "ns3::nns3",<br>
                                               "foo::(anonymous)"));<br>
 }<br>
@@ -127,7 +164,8 @@ TEST(SemaCodeCompleteTest, VisitedNSForV<br>
 TEST(SemaCodeCompleteTest, VisitedNSForInvalideQualifiedId) {<br>
   auto VisitedNS = runCodeCompleteOnCode(R"cpp(<br>
      namespace ns { foo::^ }<br>
-  )cpp");<br>
+  )cpp")<br>
+                       .VisitedNamespaces;<br>
   EXPECT_TRUE(VisitedNS.empty());<br>
 }<br>
<br>
@@ -138,8 +176,150 @@ TEST(SemaCodeCompleteTest, VisitedNSWith<br>
       void f(^) {}<br>
     }<br>
     }<br>
-  )cpp");<br>
+  )cpp")<br>
+                       .VisitedNamespaces;<br>
   EXPECT_THAT(VisitedNS, UnorderedElementsAre("n1", "n1::n2"));<br>
 }<br>
<br>
+TEST(PreferredTypeTest, BinaryExpr) {<br>
+  // Check various operations for arithmetic types.<br>
+  EXPECT_THAT(collectPreferredTypes(R"cpp(<br>
+    void test(int x) {<br>
+      x = ^10;<br>
+      x += ^10; x -= ^10; x *= ^10; x /= ^10; x %= ^10;<br>
+      x + ^10; x - ^10; x * ^10; x / ^10; x % ^10;<br>
+    })cpp"),<br>
+              Each("int"));<br>
+  EXPECT_THAT(collectPreferredTypes(R"cpp(<br>
+    void test(float x) {<br>
+      x = ^10;<br>
+      x += ^10; x -= ^10; x *= ^10; x /= ^10; x %= ^10;<br>
+      x + ^10; x - ^10; x * ^10; x / ^10; x % ^10;<br>
+    })cpp"),<br>
+              Each("float"));<br>
+<br>
+  // Pointer types.<br>
+  EXPECT_THAT(collectPreferredTypes(R"cpp(<br>
+    void test(int *ptr) {<br>
+      ptr - ^ptr;<br>
+      ptr = ^ptr;<br>
+    })cpp"),<br>
+              Each("int *"));<br>
+<br>
+  EXPECT_THAT(collectPreferredTypes(R"cpp(<br>
+    void test(int *ptr) {<br>
+      ptr + ^10;<br>
+      ptr += ^10;<br>
+      ptr -= ^10;<br>
+    })cpp"),<br>
+              Each("long")); // long is normalized 'ptrdiff_t'.<br>
+<br>
+  // Comparison operators.<br>
+  EXPECT_THAT(collectPreferredTypes(R"cpp(<br>
+    void test(int i) {<br>
+      i <= ^1; i < ^1; i >= ^1; i > ^1; i == ^1; i != ^1;<br>
+    }<br>
+  )cpp"),<br>
+              Each("int"));<br>
+<br>
+  EXPECT_THAT(collectPreferredTypes(R"cpp(<br>
+    void test(int *ptr) {<br>
+      ptr <= ^ptr; ptr < ^ptr; ptr >= ^ptr; ptr > ^ptr;<br>
+      ptr == ^ptr; ptr != ^ptr;<br>
+    }<br>
+  )cpp"),<br>
+              Each("int *"));<br>
+<br>
+  // Relational operations.<br>
+  EXPECT_THAT(collectPreferredTypes(R"cpp(<br>
+    void test(int i, int *ptr) {<br>
+      i && ^1; i || ^1;<br>
+      ptr && ^1; ptr || ^1;<br>
+    }<br>
+  )cpp"),<br>
+              Each("_Bool"));<br>
+<br>
+  // Bitwise operations.<br>
+  EXPECT_THAT(collectPreferredTypes(R"cpp(<br>
+    void test(long long ll) {<br>
+      ll | ^1; ll & ^1;<br>
+    }<br>
+  )cpp"),<br>
+              Each("long long"));<br>
+<br>
+  EXPECT_THAT(collectPreferredTypes(R"cpp(<br>
+    enum A {};<br>
+    void test(A a) {<br>
+      a | ^1; a & ^1;<br>
+    }<br>
+  )cpp"),<br>
+              Each("enum A"));<br>
+<br>
+  EXPECT_THAT(collectPreferredTypes(R"cpp(<br>
+    enum class A {};<br>
+    void test(A a) {<br>
+      // This is technically illegal with the 'enum class' without overloaded<br>
+      // operators, but we pretend it's fine.<br>
+      a | ^a; a & ^a;<br>
+    }<br>
+  )cpp"),<br>
+              Each("enum A"));<br>
+<br>
+  // Binary shifts.<br>
+  EXPECT_THAT(collectPreferredTypes(R"cpp(<br>
+    void test(int i, long long ll) {<br>
+      i << ^1; ll << ^1;<br>
+      i <<= ^1; i <<= ^1;<br>
+      i >> ^1; ll >> ^1;<br>
+      i >>= ^1; i >>= ^1;<br>
+    }<br>
+  )cpp"),<br>
+              Each("int"));<br>
+<br>
+  // Comma does not provide any useful information.<br>
+  EXPECT_THAT(collectPreferredTypes(R"cpp(<br>
+    class Cls {};<br>
+    void test(int i, int* ptr, Cls x) {<br>
+      (i, ^i);<br>
+      (ptr, ^ptr);<br>
+      (x, ^x);<br>
+    }<br>
+  )cpp"),<br>
+              Each("NULL TYPE"));<br>
+<br>
+  // User-defined types do not take operator overloading into account.<br>
+  // However, they provide heuristics for some common cases.<br>
+  EXPECT_THAT(collectPreferredTypes(R"cpp(<br>
+    class Cls {};<br>
+    void test(Cls c) {<br>
+      // we assume arithmetic and comparions ops take the same type.<br>
+      c + ^c; c - ^c; c * ^c; c / ^c; c % ^c;<br>
+      c == ^c; c != ^c; c < ^c; c <= ^c; c > ^c; c >= ^c;<br>
+      // same for the assignments.<br>
+      c = ^c; c += ^c; c -= ^c; c *= ^c; c /= ^c; c %= ^c;<br>
+    }<br>
+  )cpp"),<br>
+              Each("class Cls"));<br>
+<br>
+  EXPECT_THAT(collectPreferredTypes(R"cpp(<br>
+    class Cls {};<br>
+    void test(Cls c) {<br>
+      // we assume relational ops operate on bools.<br>
+      c && ^c; c || ^c;<br>
+    }<br>
+  )cpp"),<br>
+              Each("_Bool"));<br>
+<br>
+  EXPECT_THAT(collectPreferredTypes(R"cpp(<br>
+    class Cls {};<br>
+    void test(Cls c) {<br>
+      // we make no assumptions about the following operators, since they are<br>
+      // often overloaded with a non-standard meaning.<br>
+      c << ^c; c >> ^c; c | ^c; c & ^c;<br>
+      c <<= ^c; c >>= ^c; c |= ^c; c &= ^c;<br>
+    }<br>
+  )cpp"),<br>
+              Each("NULL TYPE"));<br>
+}<br>
+<br>
 } // namespace<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><o:p></o:p></p>
</blockquote>
</div>
</blockquote>
</div>
</div>
</body>
</html>