[PATCH] Implementation for completion in call context for C++

Manuel Klimek klimek at google.com
Thu Jan 15 01:29:05 PST 2015


Ok, I think the scope of the patch is now ok - going into detailed code review :)


================
Comment at: lib/Sema/SemaCodeComplete.cpp:3852-3858
@@ +3851,9 @@
+  else if (auto UnresExpr = dyn_cast<UnresolvedMemberExpr>(NakedFn)) {
+    CXXMethodDecl *Method = nullptr;
+    QualType ObjectType = UnresExpr->getBaseType();
+    TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = nullptr;
+    if (UnresExpr->hasExplicitTemplateArgs()) {
+      UnresExpr->copyTemplateArgumentsInto(TemplateArgsBuffer);
+      TemplateArgs = &TemplateArgsBuffer;
+    }
+    Expr::Classification ObjectClassification
----------------
Generally, try to keep the scope of variables as short as possible. Just declare stuff in the loop if it's only used there.

================
Comment at: lib/Sema/SemaCodeComplete.cpp:3855-3857
@@ -3854,5 +3918,1 @@
-                                /*PartialOverloading=*/ true);
-  else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(NakedFn)) {
-    FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl());
-    if (FDecl) {
       if (!getLangOpts().CPlusPlus || 
----------------
Why is it ok to remove the DeclRefExpr case? Where is this handled in the new code?

================
Comment at: lib/Sema/SemaCodeComplete.cpp:3859-3861
@@ +3858,5 @@
+    }
+    Expr::Classification ObjectClassification
+      = UnresExpr->isArrow()? Expr::Classification::makeSimpleLValue()
+                            : UnresExpr->getBase()->Classify(Context);
+    for (auto I = UnresExpr->decls_begin(),
----------------
This needs a comment explaining why we do that; why is it a simple lvalue if UnresExpr->isArrow()? Why not use Classify unconditionally?

================
Comment at: lib/Sema/SemaCodeComplete.cpp:3862-3863
@@ +3861,4 @@
+                            : UnresExpr->getBase()->Classify(Context);
+    for (auto I = UnresExpr->decls_begin(),
+           E = UnresExpr->decls_end(); I != E; ++I) {
+
----------------
I thought be now we should have a way to use a range based for loop here?
for (auto Decl : UnresExpr->decls()) {
  ...
}

================
Comment at: lib/Sema/SemaCodeComplete.cpp:3877
@@ +3876,3 @@
+                             /*PartialOverloading=*/true);
+      } else if ((Method = dyn_cast<CXXMethodDecl>(Func))) {
+        // If explicit template arguments were provided, we can't call a
----------------
You can declare Method in the if:
} else if (CXXMethodDecl *Method = dyn_cast...

================
Comment at: lib/Sema/SemaCodeComplete.cpp:3880
@@ +3879,3 @@
+        // non-template member function.
+        if (TemplateArgs)
+          continue;
----------------
I'd just inline UnresExpr->hasExplicitTemplateArgs() here.

================
Comment at: lib/Sema/SemaCodeComplete.cpp:3889
@@ +3888,3 @@
+        AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func),
+                                   I.getPair(), ActingDC, TemplateArgs,
+                                   ObjectType,  ObjectClassification,
----------------
Any reason to not just use &UnresExpr->getExplicitTemplateArgs()?

================
Comment at: lib/Sema/SemaCodeComplete.cpp:3896-3897
@@ +3895,4 @@
+    }
+  } else if (auto DC = NakedFn->getType()->getCanonicalTypeInternal()
+                       ->getAsCXXRecordDecl()) {
+    DeclarationName OpName = Context.DeclarationNames
----------------
This needs a comment as to what exactly we're trying to address here...

================
Comment at: lib/Sema/SemaCodeComplete.cpp:3902
@@ +3901,3 @@
+    LookupQualifiedName(R, DC);
+    R.suppressDiagnostics();
+    SmallVector<Expr*, 12> ArgExprs(1, NakedFn);
----------------
Is the suppressDiagnostics() really needed (I'm not familiar with this, so I just want to make sure :)

================
Comment at: lib/Sema/SemaCodeComplete.cpp:3912-3916
@@ +3911,7 @@
+  } else {
+    FunctionDecl *FD = nullptr;
+    if (auto MCE = dyn_cast<MemberExpr>(NakedFn))
+      FD = dyn_cast<FunctionDecl>(MCE->getMemberDecl());
+    else if (auto DRE = dyn_cast<DeclRefExpr>(NakedFn))
+      FD = dyn_cast<FunctionDecl>(DRE->getDecl());
+    if (FD) {
----------------
A short description on what we're going for here would also help tremendously :)

================
Comment at: lib/Sema/SemaCodeComplete.cpp:4006-4037
@@ -3919,2 +4005,34 @@
+
+  if (!CandidateSet.empty()) {
+    // Sort the overload candidate set by placing the best overloads first.
+    std::stable_sort(
+        CandidateSet.begin(), CandidateSet.end(),
+        [&](const OverloadCandidate &X, const OverloadCandidate &Y) {
+          return isBetterOverloadCandidate(*this, X, Y, Loc);
+        });
+
+    // Add the remaining viable overload candidates as code-completion results.
+    for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
+                                     CandEnd = CandidateSet.end();
+         Cand != CandEnd; ++Cand) {
+      if (Cand->Viable)
+        Results.push_back(ResultCandidate(Cand->Function));
+    }
+
+    // From the viable candidates, try to determine the type of this parameter.
+    for (unsigned I = 0, N = Results.size(); I != N; ++I) {
+      if (const FunctionType *FType = Results[I].getFunctionType())
+        if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FType))
+          if (Args.size() < Proto->getNumParams()) {
+            if (ParamType.isNull())
+              ParamType = Proto->getParamType(Args.size());
+            else if (!Context.hasSameUnqualifiedType(
+                          ParamType.getNonReferenceType(),
+                          Proto->getParamType(Args.size())
+                              .getNonReferenceType())) {
+              ParamType = QualType();
+              break;
+            }
+          }
     }
   }
----------------
This looks copied. Pull out a function.

================
Comment at: lib/Sema/SemaOverload.cpp:5965-5967
@@ -5959,4 +5964,5 @@
   // parameters is viable only if it has an ellipsis in its parameter
   // list (8.3.5).
-  if (Args.size() > NumParams && !Proto->isVariadic()) {
+  if ((Args.size() + (PartialOverloading && Args.size())) > NumParams &&
+      !Proto->isVariadic()) {
     Candidate.Viable = false;
----------------
Looking at this some more (and now understanding the code a bit better, thanks for explaining) I still have the feeling this is wrong.
What happens if you make this (Args.size() > NumParams)? Which tests fail?

This dubious pattern was previously used in a single location; spreading it further is actively harmful, I think, so I'd strongly vote for either making sure we don't need it, or adding comments where it is needed (or a function that is named according to what this does).

http://reviews.llvm.org/D6880

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/






More information about the cfe-commits mailing list