From: Ilya Biryukov Date: Thu, 30 Aug 2018 13:08:03 +0000 (+0000) Subject: [CodeComplete] Report location of opening parens for signature help X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8cd8ed88f9c9e6644b7a7b15ae59f3a640103fed;p=clang [CodeComplete] Report location of opening parens for signature help Summary: Used in clangd. Reviewers: sammccall Reviewed By: sammccall Subscribers: ioeric, kadircet, cfe-commits Differential Revision: https://reviews.llvm.org/D51436 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@341063 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index ede3ddf919..9a06fa813e 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -1114,9 +1114,13 @@ public: /// \param Candidates an array of overload candidates. /// /// \param NumCandidates the number of overload candidates + /// + /// \param OpenParLoc location of the opening parenthesis of the argument + /// list. virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, OverloadCandidate *Candidates, - unsigned NumCandidates) {} + unsigned NumCandidates, + SourceLocation OpenParLoc) {} //@} /// Retrieve the allocator that will be used to allocate @@ -1166,7 +1170,8 @@ public: void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, OverloadCandidate *Candidates, - unsigned NumCandidates) override; + unsigned NumCandidates, + SourceLocation OpenParLoc) override; bool isResultFilteredOut(StringRef Filter, CodeCompletionResult Results) override; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 1a4199f1db..5f6cc51569 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -10230,9 +10230,11 @@ public: const VirtSpecifiers *VS = nullptr); void CodeCompleteBracketDeclarator(Scope *S); void CodeCompleteCase(Scope *S); - void CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef Args); + void CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef Args, + SourceLocation OpenParLoc); void CodeCompleteConstructor(Scope *S, QualType Type, SourceLocation Loc, - ArrayRef Args); + ArrayRef Args, + SourceLocation OpenParLoc); void CodeCompleteInitializer(Scope *S, Decl *D); void CodeCompleteReturn(Scope *S); void CodeCompleteAfterIf(Scope *S); diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 701f07f22e..b91870c291 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -1911,8 +1911,10 @@ namespace { void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, OverloadCandidate *Candidates, - unsigned NumCandidates) override { - Next.ProcessOverloadCandidates(S, CurrentArg, Candidates, NumCandidates); + unsigned NumCandidates, + SourceLocation OpenParLoc) override { + Next.ProcessOverloadCandidates(S, CurrentArg, Candidates, NumCandidates, + OpenParLoc); } CodeCompletionAllocator &getAllocator() override { diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 04c0286ec6..5d780de8f5 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2304,7 +2304,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( auto ConstructorCompleter = [&, ThisVarDecl] { Actions.CodeCompleteConstructor( getCurScope(), ThisVarDecl->getType()->getCanonicalTypeInternal(), - ThisDecl->getLocation(), Exprs); + ThisDecl->getLocation(), Exprs, T.getOpenLocation()); }; if (ThisVarDecl) { // ParseExpressionList can sometimes succeed even when ThisDecl is not diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index d1d8507af8..39bf1c6398 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1650,7 +1650,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { CommaLocsTy CommaLocs; if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteCall(getCurScope(), LHS.get(), None); + Actions.CodeCompleteCall(getCurScope(), LHS.get(), None, + PT.getOpenLocation()); cutOffParsing(); return ExprError(); } @@ -1658,8 +1659,9 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (OpKind == tok::l_paren || !LHS.isInvalid()) { if (Tok.isNot(tok::r_paren)) { if (ParseExpressionList(ArgExprs, CommaLocs, [&] { - Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs); - })) { + Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs, + PT.getOpenLocation()); + })) { (void)Actions.CorrectDelayedTyposInExpr(LHS); LHS = ExprError(); } else if (LHS.isInvalid()) { diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 4e27ca0cea..fef01a4030 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -1687,7 +1687,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { if (ParseExpressionList(Exprs, CommaLocs, [&] { Actions.CodeCompleteConstructor( getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), - DS.getEndLoc(), Exprs); + DS.getEndLoc(), Exprs, T.getOpenLocation()); })) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); @@ -2821,7 +2821,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { DeclaratorInfo).get(); Actions.CodeCompleteConstructor( getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), - DeclaratorInfo.getEndLoc(), ConstructorArgs); + DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen); })) { SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch); return ExprError(); diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index a413e96a91..c53eae3067 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -415,11 +415,14 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) { ExprVector Exprs; CommaLocsTy CommaLocs; - if (ParseExpressionList(Exprs, CommaLocs, [this, OmpPrivParm, &Exprs] { - Actions.CodeCompleteConstructor( - getCurScope(), OmpPrivParm->getType()->getCanonicalTypeInternal(), - OmpPrivParm->getLocation(), Exprs); - })) { + SourceLocation LParLoc = T.getOpenLocation(); + if (ParseExpressionList( + Exprs, CommaLocs, [this, OmpPrivParm, LParLoc, &Exprs] { + Actions.CodeCompleteConstructor( + getCurScope(), + OmpPrivParm->getType()->getCanonicalTypeInternal(), + OmpPrivParm->getLocation(), Exprs, LParLoc); + })) { Actions.ActOnInitializerError(OmpPrivParm); SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } else { diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 8af54b9939..c7d4fc4efa 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -20,8 +20,8 @@ #include "clang/AST/DeclarationName.h" #include "clang/AST/Type.h" #include "clang/Basic/IdentifierTable.h" -#include "clang/Sema/Sema.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Sema/Sema.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -29,6 +29,7 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -624,16 +625,17 @@ static std::string getOverloadAsString(const CodeCompletionString &CCS) { return OS.str(); } -void -PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, - unsigned CurrentArg, - OverloadCandidate *Candidates, - unsigned NumCandidates) { +void PrintingCodeCompleteConsumer::ProcessOverloadCandidates( + Sema &SemaRef, unsigned CurrentArg, OverloadCandidate *Candidates, + unsigned NumCandidates, SourceLocation OpenParLoc) { + OS << "OPENING_PAREN_LOC: "; + OpenParLoc.print(OS, SemaRef.getSourceManager()); + OS << "\n"; + for (unsigned I = 0; I != NumCandidates; ++I) { - if (CodeCompletionString *CCS - = Candidates[I].CreateSignatureString(CurrentArg, SemaRef, - getAllocator(), CCTUInfo, - includeBriefComments())) { + if (CodeCompletionString *CCS = Candidates[I].CreateSignatureString( + CurrentArg, SemaRef, getAllocator(), CCTUInfo, + includeBriefComments())) { OS << "OVERLOAD: " << getOverloadAsString(*CCS) << "\n"; } } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 30af826ef6..e0adf38f93 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -4435,10 +4435,11 @@ static QualType getParamType(Sema &SemaRef, return ParamType; } -static void CodeCompleteOverloadResults(Sema &SemaRef, Scope *S, - MutableArrayRef Candidates, - unsigned CurrentArg, - bool CompleteExpressionWithCurrentArg = true) { +static void +CodeCompleteOverloadResults(Sema &SemaRef, Scope *S, + MutableArrayRef Candidates, + unsigned CurrentArg, SourceLocation OpenParLoc, + bool CompleteExpressionWithCurrentArg = true) { QualType ParamType; if (CompleteExpressionWithCurrentArg) ParamType = getParamType(SemaRef, Candidates, CurrentArg); @@ -4449,12 +4450,12 @@ static void CodeCompleteOverloadResults(Sema &SemaRef, Scope *S, SemaRef.CodeCompleteExpression(S, ParamType); if (!Candidates.empty()) - SemaRef.CodeCompleter->ProcessOverloadCandidates(SemaRef, CurrentArg, - Candidates.data(), - Candidates.size()); + SemaRef.CodeCompleter->ProcessOverloadCandidates( + SemaRef, CurrentArg, Candidates.data(), Candidates.size(), OpenParLoc); } -void Sema::CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef Args) { +void Sema::CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef Args, + SourceLocation OpenParLoc) { if (!CodeCompleter) return; @@ -4552,12 +4553,13 @@ void Sema::CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef Args) { } mergeCandidatesWithResults(*this, Results, CandidateSet, Loc); - CodeCompleteOverloadResults(*this, S, Results, Args.size(), + CodeCompleteOverloadResults(*this, S, Results, Args.size(), OpenParLoc, !CandidateSet.empty()); } void Sema::CodeCompleteConstructor(Scope *S, QualType Type, SourceLocation Loc, - ArrayRef Args) { + ArrayRef Args, + SourceLocation OpenParLoc) { if (!CodeCompleter) return; @@ -4592,7 +4594,7 @@ void Sema::CodeCompleteConstructor(Scope *S, QualType Type, SourceLocation Loc, SmallVector Results; mergeCandidatesWithResults(*this, Results, CandidateSet, Loc); - CodeCompleteOverloadResults(*this, S, Results, Args.size()); + CodeCompleteOverloadResults(*this, S, Results, Args.size(), OpenParLoc); } void Sema::CodeCompleteInitializer(Scope *S, Decl *D) { diff --git a/test/CodeCompletion/paren_locs.cpp b/test/CodeCompletion/paren_locs.cpp new file mode 100644 index 0000000000..303264cff7 --- /dev/null +++ b/test/CodeCompletion/paren_locs.cpp @@ -0,0 +1,33 @@ +void foo(int a, int b); +void foo(int a, int b, int c); + +void test() { + foo(10, ); + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:10 %s -o - \ + // RUN: | FileCheck -check-prefix=CHECK-CC1 %s + // CHECK-CC1: OPENING_PAREN_LOC: {{.*}}paren_locs.cpp:5:6 + +#define FOO foo( + FOO 10, ); +#undef FOO + // RUN: not %clang_cc1 -fsyntax-only -code-completion-at=%s:11:10 %s -o - \ + // RUN: | FileCheck -check-prefix=CHECK-CC2 %s + // CHECK-CC2: OPENING_PAREN_LOC: {{.*}}paren_locs.cpp:11:3 + + struct Foo { + Foo(int a, int b); + Foo(int a, int b, int c); + }; + Foo a(10, ); + // RUN: not %clang_cc1 -fsyntax-only -code-completion-at=%s:21:12 %s -o - \ + // RUN: | FileCheck -check-prefix=CHECK-CC3 %s + // CHECK-CC3: OPENING_PAREN_LOC: {{.*}}paren_locs.cpp:21:8 + Foo(10, ); + // RUN: not %clang_cc1 -fsyntax-only -code-completion-at=%s:25:10 %s -o - \ + // RUN: | FileCheck -check-prefix=CHECK-CC4 %s + // CHECK-CC4: OPENING_PAREN_LOC: {{.*}}paren_locs.cpp:25:6 + new Foo(10, ); + // RUN: not %clang_cc1 -fsyntax-only -code-completion-at=%s:29:15 %s -o - \ + // RUN: | FileCheck -check-prefix=CHECK-CC5 %s + // CHECK-CC5: OPENING_PAREN_LOC: {{.*}}paren_locs.cpp:29:10 +} diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index f49f9763c3..766745ddea 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -653,7 +653,8 @@ namespace { void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, OverloadCandidate *Candidates, - unsigned NumCandidates) override { + unsigned NumCandidates, + SourceLocation OpenParLoc) override { StoredResults.reserve(StoredResults.size() + NumCandidates); for (unsigned I = 0; I != NumCandidates; ++I) { CodeCompletionString *StoredCompletion