diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -1967,6 +1967,9 @@ if (FixIt.range.end == LSP.textEdit->range.start) { LSP.textEdit->newText = FixIt.newText + LSP.textEdit->newText; LSP.textEdit->range.start = FixIt.range.start; + } else if (FixIt.range.start == LSP.textEdit->range.end) { + LSP.textEdit->newText = LSP.textEdit->newText + FixIt.newText; + LSP.textEdit->range.end = FixIt.range.end; } else { LSP.additionalTextEdits.push_back(FixIt); } diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2047,7 +2047,8 @@ ExprResult ParseObjCMessageExpressionBody(SourceLocation LBracloc, SourceLocation SuperLoc, ParsedType ReceiverType, - Expr *ReceiverExpr); + Expr *ReceiverExpr, + SourceLocation InferredLBracLoc = SourceLocation()); ExprResult ParseAssignmentExprWithObjCMessageExprStart( SourceLocation LBracloc, SourceLocation SuperLoc, ParsedType ReceiverType, Expr *ReceiverExpr); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -12271,7 +12271,8 @@ void CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, ArrayRef SelIdents, bool AtArgumentExpression, - bool IsSuper = false); + bool IsSuper = false, + SourceRange InferredBrac = SourceRange()); void CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, ArrayRef SelIdents, bool AtArgumentExpression, diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1185,7 +1185,7 @@ (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) || Tok.is(tok::code_completion))) { Res = ParseObjCMessageExpressionBody(SourceLocation(), ILoc, nullptr, - nullptr); + nullptr, ILoc); break; } @@ -1219,7 +1219,7 @@ Res = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), - Ty.get(), nullptr); + Ty.get(), nullptr, ILoc); break; } } @@ -1492,7 +1492,7 @@ ConsumeAnnotationToken(); Res = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), - Ty.get(), nullptr); + Ty.get(), nullptr, Tok.getLocation()); break; } LLVM_FALLTHROUGH; diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -3145,16 +3145,27 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, SourceLocation SuperLoc, ParsedType ReceiverType, - Expr *ReceiverExpr) { + Expr *ReceiverExpr, + SourceLocation InferredLBracLoc) { InMessageExpressionRAIIObject InMessage(*this, true); if (Tok.is(tok::code_completion)) { + SourceRange InferredBrac; + if (InferredLBracLoc.isValid()) { + InferredBrac = SourceRange(InferredLBracLoc, Tok.getLocation()); + llvm::errs() << "[BUMBO] Found bracket replacement "; + llvm::errs().flush(); + // InferredBrac.dump(); + } + llvm::errs() << "[BUMBO] Triggering objc message code completion"; + llvm::errs().flush(); + if (SuperLoc.isValid()) Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, None, false); else if (ReceiverType) Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, None, - false); + false, false, InferredBrac); else Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, None, false); diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -3519,10 +3519,14 @@ } if (const auto *Method = dyn_cast(ND)) { + // FIXME:(davg): should this just be a fix it itself? + bool needRBrac = FixIts.size() == 1; Selector Sel = Method->getSelector(); if (Sel.isUnarySelector()) { Result.AddTypedTextChunk( Result.getAllocator().CopyString(Sel.getNameForSlot(0))); + if (needRBrac) + Result.AddChunk(CodeCompletionString::CK_RightBracket); return Result.TakeString(); } @@ -3605,6 +3609,8 @@ MaybeAddSentinel(PP, Method, Result); } + if (needRBrac) + Result.AddChunk(CodeCompletionString::CK_RightBracket); return Result.TakeString(); } @@ -4242,6 +4248,7 @@ ParsedType Receiver, ArrayRef SelIdents, bool AtArgumentExpression, bool IsSuper, + SourceRange BracFixIts, ResultBuilder &Results); void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, @@ -4302,8 +4309,12 @@ Scope::FunctionPrototypeScope | Scope::AtCatchScope)) == 0) { ParsedType T = DS.getRepAsType(); - if (!T.get().isNull() && T.get()->isObjCObjectOrInterfaceType()) - AddClassMessageCompletions(*this, S, T, None, false, false, Results); + if (!T.get().isNull() && T.get()->isObjCObjectOrInterfaceType()) { + // FIXME: conditionalize fix it. + SourceRange InferredBrac = SourceRange(DS.getBeginLoc(), DS.getEndLoc()); + AddClassMessageCompletions(*this, S, T, None, false, false, + InferredBrac, Results); + } } // Note that we intentionally suppress macro results here, since we do not @@ -6924,7 +6935,8 @@ DeclContext *CurContext, VisitedSelectorSet &Selectors, bool AllowSameLength, ResultBuilder &Results, bool InOriginalClass = true, - bool IsRootClass = false) { + bool IsRootClass = false, + SourceRange BracFixItsRange = SourceRange()) { typedef CodeCompletionResult Result; Container = getContainerDef(Container); ObjCInterfaceDecl *IFace = dyn_cast(Container); @@ -6947,6 +6959,13 @@ R.AllParametersAreInformative = (WantKind != MK_Any); if (!InOriginalClass) setInBaseClass(R); + if (BracFixItsRange.isValid()) { + llvm::errs() << "Adding fix its\n"; + R.FixIts.emplace_back(FixItHint::CreateInsertion(BracFixItsRange.getBegin(), "[")); + R.FixIts.emplace_back(FixItHint::CreateInsertion(BracFixItsRange.getEnd(), "]")); + } else { + llvm::errs() << "fix it range invalid\n"; + } Results.MaybeAddResult(R, CurContext); } } @@ -6960,7 +6979,8 @@ E = Protocols.end(); I != E; ++I) AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, CurContext, - Selectors, AllowSameLength, Results, false, IsRootClass); + Selectors, AllowSameLength, Results, false, IsRootClass, + BracFixItsRange); } } @@ -6970,13 +6990,14 @@ // Add methods in protocols. for (ObjCProtocolDecl *I : IFace->protocols()) AddObjCMethods(I, WantInstanceMethods, WantKind, SelIdents, CurContext, - Selectors, AllowSameLength, Results, false, IsRootClass); + Selectors, AllowSameLength, Results, false, IsRootClass, + BracFixItsRange); // Add methods in categories. for (ObjCCategoryDecl *CatDecl : IFace->known_categories()) { AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents, CurContext, Selectors, AllowSameLength, Results, - InOriginalClass, IsRootClass); + InOriginalClass, IsRootClass, BracFixItsRange); // Add a categories protocol methods. const ObjCList &Protocols = @@ -6985,13 +7006,14 @@ E = Protocols.end(); I != E; ++I) AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, CurContext, - Selectors, AllowSameLength, Results, false, IsRootClass); + Selectors, AllowSameLength, Results, false, IsRootClass, + BracFixItsRange); // Add methods in category implementations. if (ObjCCategoryImplDecl *Impl = CatDecl->getImplementation()) AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, CurContext, Selectors, AllowSameLength, Results, InOriginalClass, - IsRootClass); + IsRootClass, BracFixItsRange); } // Add methods in superclass. @@ -6999,13 +7021,14 @@ if (IFace->getSuperClass()) AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, WantKind, SelIdents, CurContext, Selectors, AllowSameLength, Results, - /*IsRootClass=*/false); + /*InOriginalClass=*/false, /*IsRootClass=*/false, + BracFixItsRange); // Add methods in our implementation, if any. if (ObjCImplementationDecl *Impl = IFace->getImplementation()) AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, CurContext, Selectors, AllowSameLength, Results, InOriginalClass, - IsRootClass); + IsRootClass, BracFixItsRange); } void Sema::CodeCompleteObjCPropertyGetter(Scope *S) { @@ -7462,10 +7485,17 @@ ParsedType Receiver, ArrayRef SelIdents, bool AtArgumentExpression, bool IsSuper, + SourceRange BracFixIts, ResultBuilder &Results) { typedef CodeCompletionResult Result; ObjCInterfaceDecl *CDecl = nullptr; + llvm::errs() << "AddClassMessageCompletions\n"; + if (BracFixIts.getBegin().isValid()) + llvm::errs() << "LBracValid\n"; + if (BracFixIts.getEnd().isValid()) + llvm::errs() << "RBracValid\n"; + // If the given name refers to an interface type, retrieve the // corresponding declaration. if (Receiver) { @@ -7495,7 +7525,8 @@ VisitedSelectorSet Selectors; if (CDecl) AddObjCMethods(CDecl, false, MK_Any, SelIdents, SemaRef.CurContext, - Selectors, AtArgumentExpression, Results); + Selectors, AtArgumentExpression, Results, false, false, + BracFixIts); else { // We're messaging "id" as a type; provide all class/factory methods. @@ -7525,6 +7556,7 @@ Results.getBasePriority(MethList->getMethod()), nullptr); R.StartParameter = SelIdents.size(); R.AllParametersAreInformative = false; + // FIXME: add it fix it here too. Results.MaybeAddResult(R, SemaRef.CurContext); } } @@ -7536,7 +7568,8 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, ArrayRef SelIdents, bool AtArgumentExpression, - bool IsSuper) { + bool IsSuper, + SourceRange InferredBrac) { QualType T = this->GetTypeFromParser(Receiver); @@ -7546,8 +7579,15 @@ CodeCompletionContext(CodeCompletionContext::CCC_ObjCClassMessage, T, SelIdents)); + llvm::errs() << "CodeCompleteObjCClassMessage\n"; + SourceRange BracFixIt; + if (CodeCompleter->includeFixIts() && InferredBrac.isValid()) { + BracFixIt = std::move(InferredBrac); + } + AddClassMessageCompletions(*this, S, Receiver, SelIdents, - AtArgumentExpression, IsSuper, Results); + AtArgumentExpression, IsSuper, + BracFixIt, Results); // If we're actually at the argument expression (rather than prior to the // selector), we're actually performing code completion for an expression.