diff options
Diffstat (limited to 'lib/Sema/SemaCodeComplete.cpp')
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 124 |
1 files changed, 86 insertions, 38 deletions
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 4de7d422072da..834e149d1af4c 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -10,10 +10,11 @@ // This file defines the code-completion semantic actions. // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/QualTypeNames.h" #include "clang/Basic/CharInfo.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/MacroInfo.h" @@ -23,6 +24,7 @@ #include "clang/Sema/Overload.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaInternal.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallPtrSet.h" @@ -46,7 +48,7 @@ namespace { /// the result set (when it returns true) and which declarations should be /// filtered out (returns false). typedef bool (ResultBuilder::*LookupFilter)(const NamedDecl *) const; - + typedef CodeCompletionResult Result; private: @@ -741,8 +743,18 @@ unsigned ResultBuilder::getBasePriority(const NamedDecl *ND) { } const DeclContext *DC = ND->getDeclContext()->getRedeclContext(); - if (DC->isRecord() || isa<ObjCContainerDecl>(DC)) + if (DC->isRecord() || isa<ObjCContainerDecl>(DC)) { + // Explicit destructor calls are very rare. + if (isa<CXXDestructorDecl>(ND)) + return CCP_Unlikely; + // Explicit operator and conversion function calls are also very rare. + auto DeclNameKind = ND->getDeclName().getNameKind(); + if (DeclNameKind == DeclarationName::CXXOperatorName || + DeclNameKind == DeclarationName::CXXLiteralOperatorName || + DeclNameKind == DeclarationName::CXXConversionFunctionName) + return CCP_Unlikely; return CCP_MemberDeclaration; + } // Content-based decisions. if (isa<EnumConstantDecl>(ND)) @@ -1070,9 +1082,16 @@ bool ResultBuilder::IsOrdinaryName(const NamedDecl *ND) const { /// ordinary name lookup but is not a type name. bool ResultBuilder::IsOrdinaryNonTypeName(const NamedDecl *ND) const { ND = cast<NamedDecl>(ND->getUnderlyingDecl()); - if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) + if (isa<TypeDecl>(ND)) return false; - + // Objective-C interfaces names are not filtered by this method because they + // can be used in a class property expression. We can still filter out + // @class declarations though. + if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(ND)) { + if (!ID->getDefinition()) + return false; + } + unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern; if (SemaRef.getLangOpts().CPlusPlus) IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace | Decl::IDNS_Member; @@ -1484,6 +1503,7 @@ static PrintingPolicy getCompletionPrintingPolicy(const ASTContext &Context, Policy.AnonymousTagLocations = false; Policy.SuppressStrongLifetime = true; Policy.SuppressUnwrittenScope = true; + Policy.SuppressScope = true; return Policy; } @@ -1647,21 +1667,23 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, if (CCC == Sema::PCC_Class) { AddTypedefResult(Results); + bool IsNotInheritanceScope = + !(S->getFlags() & Scope::ClassInheritanceScope); // public: Builder.AddTypedTextChunk("public"); - if (Results.includeCodePatterns()) + if (IsNotInheritanceScope && Results.includeCodePatterns()) Builder.AddChunk(CodeCompletionString::CK_Colon); Results.AddResult(Result(Builder.TakeString())); // protected: Builder.AddTypedTextChunk("protected"); - if (Results.includeCodePatterns()) + if (IsNotInheritanceScope && Results.includeCodePatterns()) Builder.AddChunk(CodeCompletionString::CK_Colon); Results.AddResult(Result(Builder.TakeString())); // private: Builder.AddTypedTextChunk("private"); - if (Results.includeCodePatterns()) + if (IsNotInheritanceScope && Results.includeCodePatterns()) Builder.AddChunk(CodeCompletionString::CK_Colon); Results.AddResult(Result(Builder.TakeString())); } @@ -2126,9 +2148,10 @@ static void AddResultTypeChunk(ASTContext &Context, T = Method->getSendResultType(BaseType); else T = Method->getReturnType(); - } else if (const EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND)) + } else if (const EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND)) { T = Context.getTypeDeclType(cast<TypeDecl>(Enumerator->getDeclContext())); - else if (isa<UnresolvedUsingValueDecl>(ND)) { + T = clang::TypeName::getFullyQualifiedType(T, Context); + } else if (isa<UnresolvedUsingValueDecl>(ND)) { /* Do nothing: ignore unresolved using declarations*/ } else if (const ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(ND)) { if (!BaseType.isNull()) @@ -3355,12 +3378,9 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, return; PrintingPolicy Policy = getCompletionPrintingPolicy(S); - for (CXXMethodDecl::method_iterator M = Method->begin_overridden_methods(), - MEnd = Method->end_overridden_methods(); - M != MEnd; ++M) { + for (const CXXMethodDecl *Overridden : Method->overridden_methods()) { CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); - const CXXMethodDecl *Overridden = *M; if (Overridden->getCanonicalDecl() == Method->getCanonicalDecl()) continue; @@ -4282,13 +4302,17 @@ static void mergeCandidatesWithResults(Sema &SemaRef, std::stable_sort( CandidateSet.begin(), CandidateSet.end(), [&](const OverloadCandidate &X, const OverloadCandidate &Y) { - return isBetterOverloadCandidate(SemaRef, X, Y, Loc); + return isBetterOverloadCandidate(SemaRef, X, Y, Loc, + CandidateSet.getKind()); }); // Add the remaining viable overload candidates as code-completion results. - for (auto &Candidate : CandidateSet) + for (auto &Candidate : CandidateSet) { + if (Candidate.Function && Candidate.Function->isDeleted()) + continue; if (Candidate.Viable) Results.push_back(ResultCandidate(Candidate.Function)); + } } } @@ -4379,9 +4403,11 @@ void Sema::CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef<Expr *> Args) { ArgExprs.append(Args.begin(), Args.end()); UnresolvedSet<8> Decls; Decls.append(UME->decls_begin(), UME->decls_end()); + const bool FirstArgumentIsBase = !UME->isImplicitAccess() && UME->getBase(); AddFunctionCandidates(Decls, ArgExprs, CandidateSet, TemplateArgs, /*SuppressUsedConversions=*/false, - /*PartialOverloading=*/true); + /*PartialOverloading=*/true, + FirstArgumentIsBase); } else { FunctionDecl *FD = nullptr; if (auto MCE = dyn_cast<MemberExpr>(NakedFn)) @@ -4574,9 +4600,19 @@ void Sema::CodeCompleteAssignmentRHS(Scope *S, Expr *LHS) { void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, bool EnteringContext) { - if (!SS.getScopeRep() || !CodeCompleter) + if (SS.isEmpty() || !CodeCompleter) return; + // We want to keep the scope specifier even if it's invalid (e.g. the scope + // "a::b::" is not corresponding to any context/namespace in the AST), since + // it can be useful for global code completion which have information about + // contexts/symbols that are not in the AST. + if (SS.isInvalid()) { + CodeCompletionContext CC(CodeCompletionContext::CCC_Name); + CC.setCXXScopeSpecifier(SS); + HandleCodeCompleteResults(this, CodeCompleter, CC, nullptr, 0); + return; + } // Always pretend to enter a context to ensure that a dependent type // resolves to a dependent record. DeclContext *Ctx = computeDeclContext(SS, /*EnteringContext=*/true); @@ -4592,7 +4628,7 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Name); Results.EnterNewScope(); - + // The "template" keyword can follow "::" in the grammar, but only // put it into the grammar if the nested-name-specifier is dependent. NestedNameSpecifier *NNS = SS.getScopeRep(); @@ -4606,16 +4642,21 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, // qualified-id completions. if (!EnteringContext) MaybeAddOverrideCalls(*this, Ctx, Results); - Results.ExitScope(); - - CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer, - /*IncludeGlobalScope=*/true, - /*IncludeDependentBases=*/true); + Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, - Results.getCompletionContext(), - Results.data(),Results.size()); + if (CodeCompleter->includeNamespaceLevelDecls() || + (!Ctx->isNamespace() && !Ctx->isTranslationUnit())) { + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer, + /*IncludeGlobalScope=*/true, + /*IncludeDependentBases=*/true); + } + + auto CC = Results.getCompletionContext(); + CC.setCXXScopeSpecifier(SS); + + HandleCodeCompleteResults(this, CodeCompleter, CC, Results.data(), + Results.size()); } void Sema::CodeCompleteUsing(Scope *S) { @@ -6630,7 +6671,7 @@ typedef llvm::DenseMap< /// indexed by selector so they can be easily found. static void FindImplementableMethods(ASTContext &Context, ObjCContainerDecl *Container, - bool WantInstanceMethods, + Optional<bool> WantInstanceMethods, QualType ReturnType, KnownMethodsMap &KnownMethods, bool InOriginalClass = true) { @@ -6701,7 +6742,7 @@ static void FindImplementableMethods(ASTContext &Context, // we want the methods from this container to override any methods // we've previously seen with the same selector. for (auto *M : Container->methods()) { - if (M->isInstanceMethod() == WantInstanceMethods) { + if (!WantInstanceMethods || M->isInstanceMethod() == *WantInstanceMethods) { if (!ReturnType.isNull() && !Context.hasSameUnqualifiedType(ReturnType, M->getReturnType())) continue; @@ -7373,8 +7414,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, } } -void Sema::CodeCompleteObjCMethodDecl(Scope *S, - bool IsInstanceMethod, +void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod, ParsedType ReturnTy) { // Determine the return type of the method we're declaring, if // provided. @@ -7429,7 +7469,13 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, ObjCMethodDecl *Method = M->second.getPointer(); CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); - + + // Add the '-'/'+' prefix if it wasn't provided yet. + if (!IsInstanceMethod) { + Builder.AddTextChunk(Method->isInstanceMethod() ? "-" : "+"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + } + // If the result type was not already provided, add it to the // pattern as (type). if (ReturnType.isNull()) { @@ -7531,11 +7577,13 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, if (IFace) for (auto *Cat : IFace->visible_categories()) Containers.push_back(Cat); - - for (unsigned I = 0, N = Containers.size(); I != N; ++I) - for (auto *P : Containers[I]->instance_properties()) - AddObjCKeyValueCompletions(P, IsInstanceMethod, ReturnType, Context, - KnownSelectors, Results); + + if (IsInstanceMethod) { + for (unsigned I = 0, N = Containers.size(); I != N; ++I) + for (auto *P : Containers[I]->instance_properties()) + AddObjCKeyValueCompletions(P, *IsInstanceMethod, ReturnType, Context, + KnownSelectors, Results); + } } Results.ExitScope(); |