aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaCodeComplete.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaCodeComplete.cpp')
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp161
1 files changed, 108 insertions, 53 deletions
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 8ede7c015315..144bbe150abb 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -56,6 +56,7 @@
#include <list>
#include <map>
+#include <optional>
#include <string>
#include <vector>
@@ -1098,7 +1099,8 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
getBasePriority(Using->getTargetDecl()),
R.Qualifier, false,
(R.Availability == CXAvailability_Available ||
- R.Availability == CXAvailability_Deprecated));
+ R.Availability == CXAvailability_Deprecated),
+ std::move(R.FixIts));
Result.ShadowDecl = Using;
MaybeAddResult(Result, CurContext);
return;
@@ -1212,7 +1214,7 @@ static void setInBaseClass(ResultBuilder::Result &R) {
enum class OverloadCompare { BothViable, Dominates, Dominated };
// Will Candidate ever be called on the object, when overloaded with Incumbent?
// Returns Dominates if Candidate is always called, Dominated if Incumbent is
-// always called, BothViable if either may be called dependending on arguments.
+// always called, BothViable if either may be called depending on arguments.
// Precondition: must actually be overloads!
static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate,
const CXXMethodDecl &Incumbent,
@@ -1230,8 +1232,8 @@ static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate,
if (Candidate.parameters()[I]->getType().getCanonicalType() !=
Incumbent.parameters()[I]->getType().getCanonicalType())
return OverloadCompare::BothViable;
- if (!llvm::empty(Candidate.specific_attrs<EnableIfAttr>()) ||
- !llvm::empty(Incumbent.specific_attrs<EnableIfAttr>()))
+ if (!Candidate.specific_attrs<EnableIfAttr>().empty() ||
+ !Incumbent.specific_attrs<EnableIfAttr>().empty())
return OverloadCompare::BothViable;
// At this point, we know calls can't pick one or the other based on
// arguments, so one of the two must win. (Or both fail, handled elsewhere).
@@ -1273,7 +1275,8 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
getBasePriority(Using->getTargetDecl()),
R.Qualifier, false,
(R.Availability == CXAvailability_Available ||
- R.Availability == CXAvailability_Deprecated));
+ R.Availability == CXAvailability_Deprecated),
+ std::move(R.FixIts));
Result.ShadowDecl = Using;
AddResult(Result, CurContext, Hiding);
return;
@@ -1377,6 +1380,33 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
OverloadSet.Add(Method, Results.size());
}
+ // When completing a non-static member function (and not via
+ // dot/arrow member access) and we're not inside that class' scope,
+ // it can't be a call.
+ if (CompletionContext.getKind() == clang::CodeCompletionContext::CCC_Symbol) {
+ const auto *Method = dyn_cast<CXXMethodDecl>(R.getDeclaration());
+ if (Method && !Method->isStatic()) {
+ // Find the class scope that we're currently in.
+ // We could e.g. be inside a lambda, so walk up the DeclContext until we
+ // find a CXXMethodDecl.
+ const auto *CurrentClassScope = [&]() -> const CXXRecordDecl * {
+ for (DeclContext *Ctx = SemaRef.CurContext; Ctx;
+ Ctx = Ctx->getParent()) {
+ const auto *CtxMethod = llvm::dyn_cast<CXXMethodDecl>(Ctx);
+ if (CtxMethod && !CtxMethod->getParent()->isLambda()) {
+ return CtxMethod->getParent();
+ }
+ }
+ return nullptr;
+ }();
+
+ R.FunctionCanBeCall =
+ CurrentClassScope &&
+ (CurrentClassScope == Method->getParent() ||
+ CurrentClassScope->isDerivedFrom(Method->getParent()));
+ }
+ }
+
// Insert this result into the set of results.
Results.push_back(R);
@@ -1807,7 +1837,7 @@ static void AddFunctionSpecifiers(Sema::ParserCompletionContext CCC,
Results.AddResult(Result("mutable"));
Results.AddResult(Result("virtual"));
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Sema::PCC_ObjCInterface:
case Sema::PCC_ObjCImplementation:
@@ -2095,7 +2125,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
AddObjCTopLevelResults(Results, true);
AddTypedefResult(Results);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Sema::PCC_Class:
if (SemaRef.getLangOpts().CPlusPlus) {
@@ -2153,7 +2183,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
Builder);
}
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Sema::PCC_Template:
case Sema::PCC_MemberTemplate:
@@ -2423,14 +2453,14 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
AddStaticAssertResult(Builder, Results, SemaRef.getLangOpts());
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
// Fall through (for statement expressions).
case Sema::PCC_ForInit:
case Sema::PCC_Condition:
AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results);
// Fall through: conditions and statements can have expressions.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Sema::PCC_ParenthesizedExpression:
if (SemaRef.getLangOpts().ObjCAutoRefCount &&
@@ -2460,7 +2490,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
Results.AddResult(Result(Builder.TakeString()));
}
// Fall through
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Sema::PCC_Expression: {
if (SemaRef.getLangOpts().CPlusPlus) {
@@ -2643,6 +2673,13 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
Results.AddResult(Result(Builder.TakeString()));
}
+ if (SemaRef.getLangOpts().C2x) {
+ // nullptr
+ Builder.AddResultTypeChunk("nullptr_t");
+ Builder.AddTypedTextChunk("nullptr");
+ Results.AddResult(Result(Builder.TakeString()));
+ }
+
// sizeof expression
Builder.AddResultTypeChunk("size_t");
Builder.AddTypedTextChunk("sizeof");
@@ -2783,7 +2820,7 @@ static void findTypeLocationForBlockDecl(const TypeSourceInfo *TSInfo,
while (true) {
// Look through typedefs.
if (!SuppressBlock) {
- if (TypedefTypeLoc TypedefTL = TL.getAs<TypedefTypeLoc>()) {
+ if (TypedefTypeLoc TypedefTL = TL.getAsAdjusted<TypedefTypeLoc>()) {
if (TypeSourceInfo *InnerTSInfo =
TypedefTL.getTypedefNameDecl()->getTypeSourceInfo()) {
TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc();
@@ -2814,18 +2851,16 @@ static void findTypeLocationForBlockDecl(const TypeSourceInfo *TSInfo,
}
}
-static std::string
-formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl,
- FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto,
- bool SuppressBlockName = false,
- bool SuppressBlock = false,
- Optional<ArrayRef<QualType>> ObjCSubsts = None);
+static std::string formatBlockPlaceholder(
+ const PrintingPolicy &Policy, const NamedDecl *BlockDecl,
+ FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto,
+ bool SuppressBlockName = false, bool SuppressBlock = false,
+ std::optional<ArrayRef<QualType>> ObjCSubsts = std::nullopt);
-static std::string
-FormatFunctionParameter(const PrintingPolicy &Policy,
- const DeclaratorDecl *Param, bool SuppressName = false,
- bool SuppressBlock = false,
- Optional<ArrayRef<QualType>> ObjCSubsts = None) {
+static std::string FormatFunctionParameter(
+ const PrintingPolicy &Policy, const DeclaratorDecl *Param,
+ bool SuppressName = false, bool SuppressBlock = false,
+ std::optional<ArrayRef<QualType>> ObjCSubsts = std::nullopt) {
// Params are unavailable in FunctionTypeLoc if the FunctionType is invalid.
// It would be better to pass in the param Type, which is usually available.
// But this case is rare, so just pretend we fell back to int as elsewhere.
@@ -2920,7 +2955,7 @@ static std::string
formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl,
FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto,
bool SuppressBlockName, bool SuppressBlock,
- Optional<ArrayRef<QualType>> ObjCSubsts) {
+ std::optional<ArrayRef<QualType>> ObjCSubsts) {
std::string Result;
QualType ResultType = Block.getTypePtr()->getReturnType();
if (ObjCSubsts)
@@ -3589,7 +3624,7 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
std::string Arg;
QualType ParamType = (*P)->getType();
- Optional<ArrayRef<QualType>> ObjCSubsts;
+ std::optional<ArrayRef<QualType>> ObjCSubsts;
if (!CCContext.getBaseType().isNull())
ObjCSubsts = CCContext.getBaseType()->getObjCSubstitutions(Method);
@@ -4199,7 +4234,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
// We need to have names for all of the parameters, if we're going to
// generate a forwarding call.
- for (auto P : Method->parameters())
+ for (auto *P : Method->parameters())
if (!P->getDeclName())
return;
@@ -4227,7 +4262,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
Results.getAllocator().CopyString(Overridden->getNameAsString()));
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
bool FirstParam = true;
- for (auto P : Method->parameters()) {
+ for (auto *P : Method->parameters()) {
if (FirstParam)
FirstParam = false;
else
@@ -4444,7 +4479,8 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS,
0) {
ParsedType T = DS.getRepAsType();
if (!T.get().isNull() && T.get()->isObjCObjectOrInterfaceType())
- AddClassMessageCompletions(*this, S, T, None, false, false, Results);
+ AddClassMessageCompletions(*this, S, T, std::nullopt, false, false,
+ Results);
}
// Note that we intentionally suppress macro results here, since we do not
@@ -4657,9 +4693,9 @@ static const FunctionProtoType *TryDeconstructFunctionLike(QualType T) {
// Note we only handle the sugared types, they closely match what users wrote.
// We explicitly choose to not handle ClassTemplateSpecializationDecl.
if (auto *Specialization = T->getAs<TemplateSpecializationType>()) {
- if (Specialization->getNumArgs() != 1)
+ if (Specialization->template_arguments().size() != 1)
return nullptr;
- const TemplateArgument &Argument = Specialization->getArg(0);
+ const TemplateArgument &Argument = Specialization->template_arguments()[0];
if (Argument.getKind() != TemplateArgument::Type)
return nullptr;
return Argument.getAsType()->getAs<FunctionProtoType>();
@@ -4801,7 +4837,7 @@ void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E,
if (E.isInvalid())
CodeCompleteExpression(S, PreferredType);
else if (getLangOpts().ObjC)
- CodeCompleteObjCInstanceMessage(S, E.get(), None, false);
+ CodeCompleteObjCInstanceMessage(S, E.get(), std::nullopt, false);
}
/// The set of properties that have already been added, referenced by
@@ -5045,9 +5081,11 @@ AddObjCProperties(const CodeCompletionContext &CCContext,
}
}
-static void AddRecordMembersCompletionResults(
- Sema &SemaRef, ResultBuilder &Results, Scope *S, QualType BaseType,
- ExprValueKind BaseKind, RecordDecl *RD, Optional<FixItHint> AccessOpFixIt) {
+static void
+AddRecordMembersCompletionResults(Sema &SemaRef, ResultBuilder &Results,
+ Scope *S, QualType BaseType,
+ ExprValueKind BaseKind, RecordDecl *RD,
+ std::optional<FixItHint> AccessOpFixIt) {
// Indicate that we are performing a member access, and the cv-qualifiers
// for the base object type.
Results.setObjectTypeQualifiers(BaseType.getQualifiers(), BaseKind);
@@ -5086,7 +5124,8 @@ static void AddRecordMembersCompletionResults(
// Returns the RecordDecl inside the BaseType, falling back to primary template
// in case of specializations. Since we might not have a decl for the
// instantiation/specialization yet, e.g. dependent code.
-static RecordDecl *getAsRecordDecl(const QualType BaseType) {
+static RecordDecl *getAsRecordDecl(QualType BaseType) {
+ BaseType = BaseType.getNonReferenceType();
if (auto *RD = BaseType->getAsRecordDecl()) {
if (const auto *CTSD =
llvm::dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
@@ -5145,7 +5184,7 @@ public:
// We don't have the declared parameter types, only the actual types of
// arguments we've seen. These are still valuable, as it's hard to render
// a useful function completion with neither parameter types nor names!
- llvm::Optional<SmallVector<QualType, 1>> ArgTypes;
+ std::optional<SmallVector<QualType, 1>> ArgTypes;
// Whether this is accessed as T.member, T->member, or T::member.
enum AccessOperator {
Colons,
@@ -5475,11 +5514,16 @@ private:
// We accept some lossiness (like dropping parameters).
// We only try to handle common expressions on the LHS of MemberExpr.
QualType getApproximateType(const Expr *E) {
+ if (E->getType().isNull())
+ return QualType();
+ E = E->IgnoreParenImpCasts();
QualType Unresolved = E->getType();
- if (Unresolved.isNull() ||
- !Unresolved->isSpecificBuiltinType(BuiltinType::Dependent))
- return Unresolved;
- E = E->IgnoreParens();
+ // We only resolve DependentTy, or undeduced autos (including auto* etc).
+ if (!Unresolved->isSpecificBuiltinType(BuiltinType::Dependent)) {
+ AutoType *Auto = Unresolved->getContainedAutoType();
+ if (!Auto || !Auto->isUndeducedAutoType())
+ return Unresolved;
+ }
// A call: approximate-resolve callee to a function type, get its return type
if (const CallExpr *CE = llvm::dyn_cast<CallExpr>(E)) {
QualType Callee = getApproximateType(CE->getCallee());
@@ -5542,6 +5586,13 @@ QualType getApproximateType(const Expr *E) {
}
}
}
+ // A reference to an `auto` variable: approximate-resolve its initializer.
+ if (const auto *DRE = llvm::dyn_cast<DeclRefExpr>(E)) {
+ if (const auto *VD = llvm::dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (VD->hasInit())
+ return getApproximateType(VD->getInit());
+ }
+ }
return Unresolved;
}
@@ -5600,7 +5651,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
&ResultBuilder::IsMember);
auto DoCompletion = [&](Expr *Base, bool IsArrow,
- Optional<FixItHint> AccessOpFixIt) -> bool {
+ std::optional<FixItHint> AccessOpFixIt) -> bool {
if (!Base)
return false;
@@ -5698,7 +5749,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
Results.EnterNewScope();
- bool CompletionSucceded = DoCompletion(Base, IsArrow, None);
+ bool CompletionSucceded = DoCompletion(Base, IsArrow, std::nullopt);
if (CodeCompleter->includeFixIts()) {
const CharSourceRange OpRange =
CharSourceRange::getTokenRange(OpLoc, OpLoc);
@@ -6157,8 +6208,8 @@ QualType Sema::ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args,
// Only aggregate initialization is possible, but we can't assist with it.
// Returns an out-of-range index.
// - we saw no designators, just positional arguments.
-// Returns None.
-static llvm::Optional<unsigned>
+// Returns std::nullopt.
+static std::optional<unsigned>
getNextAggregateIndexAfterDesignatedInit(const ResultCandidate &Aggregate,
ArrayRef<Expr *> Args) {
static constexpr unsigned Invalid = std::numeric_limits<unsigned>::max();
@@ -6183,7 +6234,7 @@ getNextAggregateIndexAfterDesignatedInit(const ResultCandidate &Aggregate,
}
}
if (!DesignatedFieldName)
- return llvm::None;
+ return std::nullopt;
// Find the index within the class's fields.
// (Probing getParamDecl() directly would be quadratic in number of fields).
@@ -7537,7 +7588,8 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S) {
Results.EnterNewScope();
VisitedSelectorSet Selectors;
- AddObjCMethods(Class, true, MK_ZeroArgSelector, None, CurContext, Selectors,
+ AddObjCMethods(Class, true, MK_ZeroArgSelector, std::nullopt, CurContext,
+ Selectors,
/*AllowSameLength=*/true, Results);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
@@ -7563,7 +7615,8 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S) {
Results.EnterNewScope();
VisitedSelectorSet Selectors;
- AddObjCMethods(Class, true, MK_OneArgSelector, None, CurContext, Selectors,
+ AddObjCMethods(Class, true, MK_OneArgSelector, std::nullopt, CurContext,
+ Selectors,
/*AllowSameLength=*/true, Results);
Results.ExitScope();
@@ -7859,7 +7912,8 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) {
if (Iface->getSuperClass()) {
Results.AddResult(Result("super"));
- AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, None, Results);
+ AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, std::nullopt,
+ Results);
}
if (getLangOpts().CPlusPlus11)
@@ -8505,7 +8559,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_ObjCCategoryName);
- // Add all of the categories that have have corresponding interface
+ // Add all of the categories that have corresponding interface
// declarations in this class and any of its superclasses, except for
// already-implemented categories in the class itself.
llvm::SmallPtrSet<IdentifierInfo *, 16> CategoryNames;
@@ -8669,7 +8723,7 @@ typedef llvm::DenseMap<Selector,
/// indexed by selector so they can be easily found.
static void FindImplementableMethods(ASTContext &Context,
ObjCContainerDecl *Container,
- Optional<bool> WantInstanceMethods,
+ std::optional<bool> WantInstanceMethods,
QualType ReturnType,
KnownMethodsMap &KnownMethods,
bool InOriginalClass = true) {
@@ -9393,7 +9447,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
}
}
-void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod,
+void Sema::CodeCompleteObjCMethodDecl(Scope *S,
+ std::optional<bool> IsInstanceMethod,
ParsedType ReturnTy) {
// Determine the return type of the method we're declaring, if
// provided.
@@ -9978,10 +10033,10 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) {
break;
case llvm::sys::fs::file_type::regular_file: {
// Only files that really look like headers. (Except in special dirs).
- // Header extensions from Types.def, which we can't depend on here.
const bool IsHeader = Filename.endswith_insensitive(".h") ||
Filename.endswith_insensitive(".hh") ||
Filename.endswith_insensitive(".hpp") ||
+ Filename.endswith_insensitive(".hxx") ||
Filename.endswith_insensitive(".inc") ||
(ExtensionlessHeaders && !Filename.contains('.'));
if (!IsHeader)
@@ -10048,7 +10103,7 @@ void Sema::CodeCompleteAvailabilityPlatformName() {
CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
static const char *Platforms[] = {"macOS", "iOS", "watchOS", "tvOS"};
- for (const char *Platform : llvm::makeArrayRef(Platforms)) {
+ for (const char *Platform : llvm::ArrayRef(Platforms)) {
Results.AddResult(CodeCompletionResult(Platform));
Results.AddResult(CodeCompletionResult(Results.getAllocator().CopyString(
Twine(Platform) + "ApplicationExtension")));