diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 53 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExprCXX.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Parse/ParseStmt.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaCodeComplete.cpp | 311 |
5 files changed, 245 insertions, 131 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index bbead42f031..a3080e64b00 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2293,7 +2293,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( return nullptr; } - ExprResult Init(ParseInitializer()); + PreferredType.enterVariableInit(Tok.getLocation(), ThisDecl); + ExprResult Init = ParseInitializer(); // If this is the only decl in (possibly) range based for statement, // our best guess is that the user meant ':' instead of '='. diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index d3787b9760d..1146afd134c 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -158,7 +158,8 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { /// Parse an expr that doesn't include (top-level) commas. ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); + Actions.CodeCompleteExpression(getCurScope(), + PreferredType.get(Tok.getLocation())); cutOffParsing(); return ExprError(); } @@ -271,7 +272,10 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { getLangOpts().CPlusPlus11); SourceLocation ColonLoc; + auto SavedType = PreferredType; while (1) { + // Every iteration may rely on a preferred type for the whole expression. + PreferredType = SavedType; // If this token has a lower precedence than we are allowed to parse (e.g. // because we are called recursively, or because the token is not a binop), // then we are done! @@ -392,15 +396,8 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { } } - // Code completion for the right-hand side of a binary expression goes - // through a special hook that takes the left-hand side into account. - if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteBinaryRHS(getCurScope(), LHS.get(), - OpToken.getKind()); - cutOffParsing(); - return ExprError(); - } - + PreferredType.enterBinary(Actions, Tok.getLocation(), LHS.get(), + OpToken.getKind()); // Parse another leaf here for the RHS of the operator. // ParseCastExpression works here because all RHS expressions in C have it // as a prefix, at least. However, in C++, an assignment-expression could @@ -763,6 +760,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isVectorLiteral) { ExprResult Res; tok::TokenKind SavedKind = Tok.getKind(); + auto SavedType = PreferredType; NotCastExpr = false; // This handles all of cast-expression, unary-expression, postfix-expression, @@ -1114,6 +1112,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // -- cast-expression Token SavedTok = Tok; ConsumeToken(); + + PreferredType.enterUnary(Actions, Tok.getLocation(), SavedTok.getKind(), + SavedTok.getLocation()); // One special case is implicitly handled here: if the preceding tokens are // an ambiguous cast expression, such as "(T())++", then we recurse to // determine whether the '++' is prefix or postfix. @@ -1135,6 +1136,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::amp: { // unary-expression: '&' cast-expression // Special treatment because of member pointers SourceLocation SavedLoc = ConsumeToken(); + PreferredType.enterUnary(Actions, Tok.getLocation(), tok::amp, SavedLoc); Res = ParseCastExpression(false, true); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); @@ -1149,6 +1151,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___real: // unary-expression: '__real' cast-expression [GNU] case tok::kw___imag: { // unary-expression: '__imag' cast-expression [GNU] SourceLocation SavedLoc = ConsumeToken(); + PreferredType.enterUnary(Actions, Tok.getLocation(), SavedKind, SavedLoc); Res = ParseCastExpression(false); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); @@ -1423,7 +1426,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, Res = ParseBlockLiteralExpression(); break; case tok::code_completion: { - Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); + Actions.CodeCompleteExpression(getCurScope(), + PreferredType.get(Tok.getLocation())); cutOffParsing(); return ExprError(); } @@ -1458,6 +1462,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // that the address of the function is being taken, which is illegal in CL. // These can be followed by postfix-expr pieces. + PreferredType = SavedType; Res = ParsePostfixExpressionSuffix(Res); if (getLangOpts().OpenCL) if (Expr *PostfixExpr = Res.get()) { @@ -1497,13 +1502,17 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // Now that the primary-expression piece of the postfix-expression has been // parsed, see if there are any postfix-expression pieces here. SourceLocation Loc; + auto SavedType = PreferredType; while (1) { + // Each iteration relies on preferred type for the whole expression. + PreferredType = SavedType; switch (Tok.getKind()) { case tok::code_completion: if (InMessageExpression) return LHS; - Actions.CodeCompletePostfixExpression(getCurScope(), LHS); + Actions.CodeCompletePostfixExpression( + getCurScope(), LHS, PreferredType.get(Tok.getLocation())); cutOffParsing(); return ExprError(); @@ -1545,6 +1554,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { Loc = T.getOpenLocation(); ExprResult Idx, Length; SourceLocation ColonLoc; + PreferredType.enterSubscript(Actions, Tok.getLocation(), LHS.get()); if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); Idx = ParseBraceInitializer(); @@ -1726,6 +1736,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { bool MayBePseudoDestructor = false; Expr* OrigLHS = !LHS.isInvalid() ? LHS.get() : nullptr; + PreferredType.enterMemAccess(Actions, Tok.getLocation(), OrigLHS); + if (getLangOpts().CPlusPlus && !LHS.isInvalid()) { Expr *Base = OrigLHS; const Type* BaseType = Base->getType().getTypePtrOrNull(); @@ -1772,7 +1784,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // Code completion for a member access expression. Actions.CodeCompleteMemberReferenceExpr( getCurScope(), Base, CorrectedBase, OpLoc, OpKind == tok::arrow, - Base && ExprStatementTokLoc == Base->getBeginLoc()); + Base && ExprStatementTokLoc == Base->getBeginLoc(), + PreferredType.get(Tok.getLocation())); cutOffParsing(); return ExprError(); @@ -2326,14 +2339,16 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, return ExprError(); SourceLocation OpenLoc = T.getOpenLocation(); + PreferredType.enterParenExpr(Tok.getLocation(), OpenLoc); + ExprResult Result(true); bool isAmbiguousTypeId; CastTy = nullptr; if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteOrdinaryName(getCurScope(), - ExprType >= CompoundLiteral? Sema::PCC_ParenthesizedExpression - : Sema::PCC_Expression); + Actions.CodeCompleteExpression( + getCurScope(), PreferredType.get(Tok.getLocation()), + /*IsParenthesized=*/ExprType >= CompoundLiteral); cutOffParsing(); return ExprError(); } @@ -2414,6 +2429,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, T.consumeClose(); ColonProtection.restore(); RParenLoc = T.getCloseLocation(); + + PreferredType.enterTypeCast(Tok.getLocation(), Ty.get().get()); ExprResult SubExpr = ParseCastExpression(/*isUnaryExpression=*/false); if (Ty.isInvalid() || SubExpr.isInvalid()) @@ -2544,6 +2561,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, return ExprError(); } + PreferredType.enterTypeCast(Tok.getLocation(), CastTy.get()); // Parse the cast-expression that follows it next. // TODO: For cast expression with CastTy. Result = ParseCastExpression(/*isUnaryExpression=*/false, @@ -2845,7 +2863,8 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs, if (Completer) Completer(); else - Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); + Actions.CodeCompleteExpression(getCurScope(), + PreferredType.get(Tok.getLocation())); cutOffParsing(); return true; } diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 00f369f2d71..6ef24058a16 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1672,6 +1672,8 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); + PreferredType.enterTypeCast(Tok.getLocation(), TypeRep.get()); + ExprVector Exprs; CommaLocsTy CommaLocs; @@ -1739,6 +1741,7 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, Sema::ConditionKind CK, ForRangeInfo *FRI) { ParenBraceBracketBalancer BalancerRAIIObj(*this); + PreferredType.enterCondition(Actions, Tok.getLocation()); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition); @@ -1858,6 +1861,7 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, diag::warn_cxx98_compat_generalized_initializer_lists); InitExpr = ParseBraceInitializer(); } else if (CopyInitialization) { + PreferredType.enterVariableInit(Tok.getLocation(), DeclOut); InitExpr = ParseAssignmentExpression(); } else if (Tok.is(tok::l_paren)) { // This was probably an attempt to initialize the variable. diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 5eab45a702c..3fc29253f09 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1970,9 +1970,12 @@ StmtResult Parser::ParseReturnStatement() { ExprResult R; if (Tok.isNot(tok::semi)) { + if (!IsCoreturn) + PreferredType.enterReturn(Actions, Tok.getLocation()); // FIXME: Code completion for co_return. if (Tok.is(tok::code_completion) && !IsCoreturn) { - Actions.CodeCompleteReturn(getCurScope()); + Actions.CodeCompleteExpression(getCurScope(), + PreferredType.get(Tok.getLocation())); cutOffParsing(); return StmtError(); } diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index a88e15cb55d..03d612a3e98 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -347,6 +347,182 @@ public: }; } // namespace +void PreferredTypeBuilder::enterReturn(Sema &S, SourceLocation Tok) { + if (isa<BlockDecl>(S.CurContext)) { + if (sema::BlockScopeInfo *BSI = S.getCurBlock()) { + Type = BSI->ReturnType; + ExpectedLoc = Tok; + } + } else if (const auto *Function = dyn_cast<FunctionDecl>(S.CurContext)) { + Type = Function->getReturnType(); + ExpectedLoc = Tok; + } else if (const auto *Method = dyn_cast<ObjCMethodDecl>(S.CurContext)) { + Type = Method->getReturnType(); + ExpectedLoc = Tok; + } +} + +void PreferredTypeBuilder::enterVariableInit(SourceLocation Tok, Decl *D) { + auto *VD = llvm::dyn_cast_or_null<ValueDecl>(D); + Type = VD ? VD->getType() : QualType(); + ExpectedLoc = Tok; +} + +void PreferredTypeBuilder::enterParenExpr(SourceLocation Tok, + SourceLocation LParLoc) { + // expected type for parenthesized expression does not change. + if (ExpectedLoc == LParLoc) + ExpectedLoc = Tok; +} + +static QualType getPreferredTypeOfBinaryRHS(Sema &S, Expr *LHS, + tok::TokenKind Op) { + if (!LHS) + return QualType(); + + QualType LHSType = LHS->getType(); + if (LHSType->isPointerType()) { + if (Op == tok::plus || Op == tok::plusequal || Op == tok::minusequal) + return S.getASTContext().getPointerDiffType(); + // Pointer difference is more common than subtracting an int from a pointer. + if (Op == tok::minus) + return LHSType; + } + + switch (Op) { + // No way to infer the type of RHS from LHS. + case tok::comma: + return QualType(); + // Prefer the type of the left operand for all of these. + // Arithmetic operations. + case tok::plus: + case tok::plusequal: + case tok::minus: + case tok::minusequal: + case tok::percent: + case tok::percentequal: + case tok::slash: + case tok::slashequal: + case tok::star: + case tok::starequal: + // Assignment. + case tok::equal: + // Comparison operators. + case tok::equalequal: + case tok::exclaimequal: + case tok::less: + case tok::lessequal: + case tok::greater: + case tok::greaterequal: + case tok::spaceship: + return LHS->getType(); + // Binary shifts are often overloaded, so don't try to guess those. + case tok::greatergreater: + case tok::greatergreaterequal: + case tok::lessless: + case tok::lesslessequal: + if (LHSType->isIntegralOrEnumerationType()) + return S.getASTContext().IntTy; + return QualType(); + // Logical operators, assume we want bool. + case tok::ampamp: + case tok::pipepipe: + case tok::caretcaret: + return S.getASTContext().BoolTy; + // Operators often used for bit manipulation are typically used with the type + // of the left argument. + case tok::pipe: + case tok::pipeequal: + case tok::caret: + case tok::caretequal: + case tok::amp: + case tok::ampequal: + if (LHSType->isIntegralOrEnumerationType()) + return LHSType; + return QualType(); + // RHS should be a pointer to a member of the 'LHS' type, but we can't give + // any particular type here. + case tok::periodstar: + case tok::arrowstar: + return QualType(); + default: + // FIXME(ibiryukov): handle the missing op, re-add the assertion. + // assert(false && "unhandled binary op"); + return QualType(); + } +} + +/// Get preferred type for an argument of an unary expression. \p ContextType is +/// preferred type of the whole unary expression. +static QualType getPreferredTypeOfUnaryArg(Sema &S, QualType ContextType, + tok::TokenKind Op) { + switch (Op) { + case tok::exclaim: + return S.getASTContext().BoolTy; + case tok::amp: + if (!ContextType.isNull() && ContextType->isPointerType()) + return ContextType->getPointeeType(); + return QualType(); + case tok::star: + if (ContextType.isNull()) + return QualType(); + return S.getASTContext().getPointerType(ContextType.getNonReferenceType()); + case tok::plus: + case tok::minus: + case tok::tilde: + case tok::minusminus: + case tok::plusplus: + if (ContextType.isNull()) + return S.getASTContext().IntTy; + // leave as is, these operators typically return the same type. + return ContextType; + case tok::kw___real: + case tok::kw___imag: + return QualType(); + default: + assert(false && "unhnalded unary op"); + return QualType(); + } +} + +void PreferredTypeBuilder::enterBinary(Sema &S, SourceLocation Tok, Expr *LHS, + tok::TokenKind Op) { + Type = getPreferredTypeOfBinaryRHS(S, LHS, Op); + ExpectedLoc = Tok; +} + +void PreferredTypeBuilder::enterMemAccess(Sema &S, SourceLocation Tok, + Expr *Base) { + if (!Base) + return; + Type = this->get(Base->getBeginLoc()); + ExpectedLoc = Tok; +} + +void PreferredTypeBuilder::enterUnary(Sema &S, SourceLocation Tok, + tok::TokenKind OpKind, + SourceLocation OpLoc) { + Type = getPreferredTypeOfUnaryArg(S, this->get(OpLoc), OpKind); + ExpectedLoc = Tok; +} + +void PreferredTypeBuilder::enterSubscript(Sema &S, SourceLocation Tok, + Expr *LHS) { + Type = S.getASTContext().IntTy; + ExpectedLoc = Tok; +} + +void PreferredTypeBuilder::enterTypeCast(SourceLocation Tok, + QualType CastType) { + Type = !CastType.isNull() ? CastType.getCanonicalType() : QualType(); + ExpectedLoc = Tok; +} + +void PreferredTypeBuilder::enterCondition(Sema &S, SourceLocation Tok) { + Type = S.getASTContext().BoolTy; + ExpectedLoc = Tok; +} + class ResultBuilder::ShadowMapEntry::iterator { llvm::PointerUnion<const NamedDecl *, const DeclIndexPair *> DeclOrIterator; unsigned SingleDeclIndex; @@ -3856,13 +4032,15 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, } struct Sema::CodeCompleteExpressionData { - CodeCompleteExpressionData(QualType PreferredType = QualType()) + CodeCompleteExpressionData(QualType PreferredType = QualType(), + bool IsParenthesized = false) : PreferredType(PreferredType), IntegralConstantExpression(false), - ObjCCollection(false) {} + ObjCCollection(false), IsParenthesized(IsParenthesized) {} QualType PreferredType; bool IntegralConstantExpression; bool ObjCCollection; + bool IsParenthesized; SmallVector<Decl *, 4> IgnoreDecls; }; @@ -3873,13 +4051,18 @@ void Sema::CodeCompleteExpression(Scope *S, ResultBuilder Results( *this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), - CodeCompletionContext(CodeCompletionContext::CCC_Expression, - Data.PreferredType)); + CodeCompletionContext( + Data.IsParenthesized + ? CodeCompletionContext::CCC_ParenthesizedExpression + : CodeCompletionContext::CCC_Expression, + Data.PreferredType)); + auto PCC = + Data.IsParenthesized ? PCC_ParenthesizedExpression : PCC_Expression; if (Data.ObjCCollection) Results.setFilter(&ResultBuilder::IsObjCCollection); else if (Data.IntegralConstantExpression) Results.setFilter(&ResultBuilder::IsIntegralConstantValue); - else if (WantTypesInContext(PCC_Expression, getLangOpts())) + else if (WantTypesInContext(PCC, getLangOpts())) Results.setFilter(&ResultBuilder::IsOrdinaryName); else Results.setFilter(&ResultBuilder::IsOrdinaryNonTypeName); @@ -3897,7 +4080,7 @@ void Sema::CodeCompleteExpression(Scope *S, CodeCompleter->loadExternal()); Results.EnterNewScope(); - AddOrdinaryNameResults(PCC_Expression, S, *this, Results); + AddOrdinaryNameResults(PCC, S, *this, Results); Results.ExitScope(); bool PreferredTypeIsPointer = false; @@ -3917,13 +4100,16 @@ void Sema::CodeCompleteExpression(Scope *S, Results.data(), Results.size()); } -void Sema::CodeCompleteExpression(Scope *S, QualType PreferredType) { - return CodeCompleteExpression(S, CodeCompleteExpressionData(PreferredType)); +void Sema::CodeCompleteExpression(Scope *S, QualType PreferredType, + bool IsParenthesized) { + return CodeCompleteExpression( + S, CodeCompleteExpressionData(PreferredType, IsParenthesized)); } -void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E) { +void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E, + QualType PreferredType) { if (E.isInvalid()) - CodeCompleteOrdinaryName(S, PCC_RecoveryInFunction); + CodeCompleteExpression(S, PreferredType); else if (getLangOpts().ObjC) CodeCompleteObjCInstanceMessage(S, E.get(), None, false); } @@ -4211,7 +4397,8 @@ AddRecordMembersCompletionResults(Sema &SemaRef, ResultBuilder &Results, void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, Expr *OtherOpBase, SourceLocation OpLoc, bool IsArrow, - bool IsBaseExprStatement) { + bool IsBaseExprStatement, + QualType PreferredType) { if (!Base || !CodeCompleter) return; @@ -4239,6 +4426,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, } CodeCompletionContext CCContext(contextKind, ConvertedBaseType); + CCContext.setPreferredType(PreferredType); ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CCContext, &ResultBuilder::IsMember); @@ -4800,22 +4988,6 @@ void Sema::CodeCompleteInitializer(Scope *S, Decl *D) { CodeCompleteExpression(S, Data); } -void Sema::CodeCompleteReturn(Scope *S) { - QualType ResultType; - if (isa<BlockDecl>(CurContext)) { - if (BlockScopeInfo *BSI = getCurBlock()) - ResultType = BSI->ReturnType; - } else if (const auto *Function = dyn_cast<FunctionDecl>(CurContext)) - ResultType = Function->getReturnType(); - else if (const auto *Method = dyn_cast<ObjCMethodDecl>(CurContext)) - ResultType = Method->getReturnType(); - - if (ResultType.isNull()) - CodeCompleteOrdinaryName(S, PCC_Expression); - else - CodeCompleteExpression(S, ResultType); -} - void Sema::CodeCompleteAfterIf(Scope *S) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), @@ -4877,91 +5049,6 @@ void Sema::CodeCompleteAfterIf(Scope *S) { Results.data(), Results.size()); } -static QualType getPreferredTypeOfBinaryRHS(Sema &S, Expr *LHS, - tok::TokenKind Op) { - if (!LHS) - return QualType(); - - QualType LHSType = LHS->getType(); - if (LHSType->isPointerType()) { - if (Op == tok::plus || Op == tok::plusequal || Op == tok::minusequal) - return S.getASTContext().getPointerDiffType(); - // Pointer difference is more common than subtracting an int from a pointer. - if (Op == tok::minus) - return LHSType; - } - - switch (Op) { - // No way to infer the type of RHS from LHS. - case tok::comma: - return QualType(); - // Prefer the type of the left operand for all of these. - // Arithmetic operations. - case tok::plus: - case tok::plusequal: - case tok::minus: - case tok::minusequal: - case tok::percent: - case tok::percentequal: - case tok::slash: - case tok::slashequal: - case tok::star: - case tok::starequal: - // Assignment. - case tok::equal: - // Comparison operators. - case tok::equalequal: - case tok::exclaimequal: - case tok::less: - case tok::lessequal: - case tok::greater: - case tok::greaterequal: - case tok::spaceship: - return LHS->getType(); - // Binary shifts are often overloaded, so don't try to guess those. - case tok::greatergreater: - case tok::greatergreaterequal: - case tok::lessless: - case tok::lesslessequal: - if (LHSType->isIntegralOrEnumerationType()) - return S.getASTContext().IntTy; - return QualType(); - // Logical operators, assume we want bool. - case tok::ampamp: - case tok::pipepipe: - case tok::caretcaret: - return S.getASTContext().BoolTy; - // Operators often used for bit manipulation are typically used with the type - // of the left argument. - case tok::pipe: - case tok::pipeequal: - case tok::caret: - case tok::caretequal: - case tok::amp: - case tok::ampequal: - if (LHSType->isIntegralOrEnumerationType()) - return LHSType; - return QualType(); - // RHS should be a pointer to a member of the 'LHS' type, but we can't give - // any particular type here. - case tok::periodstar: - case tok::arrowstar: - return QualType(); - default: - // FIXME(ibiryukov): handle the missing op, re-add the assertion. - // assert(false && "unhandled binary op"); - return QualType(); - } -} - -void Sema::CodeCompleteBinaryRHS(Scope *S, Expr *LHS, tok::TokenKind Op) { - auto PreferredType = getPreferredTypeOfBinaryRHS(*this, LHS, Op); - if (!PreferredType.isNull()) - CodeCompleteExpression(S, PreferredType); - else - CodeCompleteOrdinaryName(S, PCC_Expression); -} - void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, bool EnteringContext, QualType BaseType) { if (SS.isEmpty() || !CodeCompleter) |