forked from qt-creator/qt-creator
Clang: Add semantic C++ operator-token styling
We used to style overloaded operators in the same way as C++'s built-in operators. There was no way to tell if a + token would call a operator+() function or not. Now, if an operator is overloaded (redefined), we give it the "Overloaded Operator"-mixin so users can style it differently. Note: Calls to overloaded 'new' and 'delete' are not highlighted by "Overloaded Operator". This is because clang today always maps these to CXCursor_CXXNewExpr and CXCursor_CXXDeleteExpr with cursor.spelling == "" (empty string). So there is no (?) quick way for us to tell if a new/delete-token was overloaded or not. After follow-ups, follow symbol will work for operator overload usages in current translation unit. Commit is appended by Ivan Donchevskii. Task-number: QTCREATORBUG-19659 Change-Id: I157855d482a61ad2059642a1ee982089fcb7d312 Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
@@ -82,6 +82,7 @@ enum class HighlightingType : quint8
|
|||||||
GlobalVariable,
|
GlobalVariable,
|
||||||
Enumeration,
|
Enumeration,
|
||||||
Operator,
|
Operator,
|
||||||
|
OverloadedOperator,
|
||||||
Preprocessor,
|
Preprocessor,
|
||||||
PreprocessorDefinition,
|
PreprocessorDefinition,
|
||||||
PreprocessorExpansion,
|
PreprocessorExpansion,
|
||||||
|
@@ -46,6 +46,7 @@ static const char *highlightingTypeToCStringLiteral(HighlightingType type)
|
|||||||
RETURN_TEXT_FOR_CASE(Field);
|
RETURN_TEXT_FOR_CASE(Field);
|
||||||
RETURN_TEXT_FOR_CASE(Enumeration);
|
RETURN_TEXT_FOR_CASE(Enumeration);
|
||||||
RETURN_TEXT_FOR_CASE(Operator);
|
RETURN_TEXT_FOR_CASE(Operator);
|
||||||
|
RETURN_TEXT_FOR_CASE(OverloadedOperator);
|
||||||
RETURN_TEXT_FOR_CASE(Preprocessor);
|
RETURN_TEXT_FOR_CASE(Preprocessor);
|
||||||
RETURN_TEXT_FOR_CASE(Label);
|
RETURN_TEXT_FOR_CASE(Label);
|
||||||
RETURN_TEXT_FOR_CASE(FunctionDefinition);
|
RETURN_TEXT_FOR_CASE(FunctionDefinition);
|
||||||
@@ -67,6 +68,8 @@ static const char *highlightingTypeToCStringLiteral(HighlightingType type)
|
|||||||
RETURN_TEXT_FOR_CASE(ObjectiveCImplementation);
|
RETURN_TEXT_FOR_CASE(ObjectiveCImplementation);
|
||||||
RETURN_TEXT_FOR_CASE(ObjectiveCProperty);
|
RETURN_TEXT_FOR_CASE(ObjectiveCProperty);
|
||||||
RETURN_TEXT_FOR_CASE(ObjectiveCMethod);
|
RETURN_TEXT_FOR_CASE(ObjectiveCMethod);
|
||||||
|
RETURN_TEXT_FOR_CASE(PrimitiveType);
|
||||||
|
RETURN_TEXT_FOR_CASE(Declaration);
|
||||||
default: return "UnhandledHighlightingType";
|
default: return "UnhandledHighlightingType";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -70,6 +70,8 @@ TextEditor::TextStyle toTextStyle(ClangBackEnd::HighlightingType type)
|
|||||||
return TextEditor::C_OUTPUT_ARGUMENT;
|
return TextEditor::C_OUTPUT_ARGUMENT;
|
||||||
case HighlightingType::Operator:
|
case HighlightingType::Operator:
|
||||||
return TextEditor::C_OPERATOR;
|
return TextEditor::C_OPERATOR;
|
||||||
|
case HighlightingType::OverloadedOperator:
|
||||||
|
return TextEditor::C_OVERLOADED_OPERATOR;
|
||||||
case HighlightingType::Comment:
|
case HighlightingType::Comment:
|
||||||
return TextEditor::C_COMMENT;
|
return TextEditor::C_COMMENT;
|
||||||
case HighlightingType::StringLiteral:
|
case HighlightingType::StringLiteral:
|
||||||
|
@@ -255,7 +255,8 @@ CPlusPlus::Icons::IconType iconTypeForToken(const ClangBackEnd::TokenInfoContain
|
|||||||
|
|
||||||
ClangBackEnd::StorageClass storageClass = extraInfo.storageClass;
|
ClangBackEnd::StorageClass storageClass = extraInfo.storageClass;
|
||||||
if (mainType == ClangBackEnd::HighlightingType::VirtualFunction
|
if (mainType == ClangBackEnd::HighlightingType::VirtualFunction
|
||||||
|| mainType == ClangBackEnd::HighlightingType::Function) {
|
|| mainType == ClangBackEnd::HighlightingType::Function
|
||||||
|
|| mainType == ClangBackEnd::HighlightingType::Operator) {
|
||||||
if (storageClass != ClangBackEnd::StorageClass::Static) {
|
if (storageClass != ClangBackEnd::StorageClass::Static) {
|
||||||
switch (access) {
|
switch (access) {
|
||||||
case ClangBackEnd::AccessSpecifier::Public:
|
case ClangBackEnd::AccessSpecifier::Public:
|
||||||
|
@@ -63,6 +63,7 @@ const char *nameForStyle(TextStyle style)
|
|||||||
case C_KEYWORD: return "Keyword";
|
case C_KEYWORD: return "Keyword";
|
||||||
case C_PRIMITIVE_TYPE: return "PrimitiveType";
|
case C_PRIMITIVE_TYPE: return "PrimitiveType";
|
||||||
case C_OPERATOR: return "Operator";
|
case C_OPERATOR: return "Operator";
|
||||||
|
case C_OVERLOADED_OPERATOR: return "Overloaded Operator";
|
||||||
case C_PREPROCESSOR: return "Preprocessor";
|
case C_PREPROCESSOR: return "Preprocessor";
|
||||||
case C_LABEL: return "Label";
|
case C_LABEL: return "Label";
|
||||||
case C_COMMENT: return "Comment";
|
case C_COMMENT: return "Comment";
|
||||||
|
@@ -59,6 +59,7 @@ enum TextStyle : quint8 {
|
|||||||
C_KEYWORD,
|
C_KEYWORD,
|
||||||
C_PRIMITIVE_TYPE,
|
C_PRIMITIVE_TYPE,
|
||||||
C_OPERATOR,
|
C_OPERATOR,
|
||||||
|
C_OVERLOADED_OPERATOR,
|
||||||
C_PREPROCESSOR,
|
C_PREPROCESSOR,
|
||||||
C_LABEL,
|
C_LABEL,
|
||||||
C_COMMENT,
|
C_COMMENT,
|
||||||
|
@@ -226,7 +226,8 @@ TextEditorSettings::TextEditorSettings()
|
|||||||
tr("Reserved keywords of the programming language except "
|
tr("Reserved keywords of the programming language except "
|
||||||
"keywords denoting primitive types."), Qt::darkYellow);
|
"keywords denoting primitive types."), Qt::darkYellow);
|
||||||
formatDescr.emplace_back(C_OPERATOR, tr("Operator"),
|
formatDescr.emplace_back(C_OPERATOR, tr("Operator"),
|
||||||
tr("Operators (for example operator++ or operator-=)."));
|
tr("Non user-defined language operators.\n"
|
||||||
|
"To style user-defined operators, use Overloaded Operator."));
|
||||||
formatDescr.emplace_back(C_PREPROCESSOR, tr("Preprocessor"),
|
formatDescr.emplace_back(C_PREPROCESSOR, tr("Preprocessor"),
|
||||||
tr("Preprocessor directives."), Qt::darkBlue);
|
tr("Preprocessor directives."), Qt::darkBlue);
|
||||||
formatDescr.emplace_back(C_LABEL, tr("Label"), tr("Labels for goto statements."),
|
formatDescr.emplace_back(C_LABEL, tr("Label"), tr("Labels for goto statements."),
|
||||||
@@ -313,6 +314,10 @@ TextEditorSettings::TextEditorSettings()
|
|||||||
QColor(255, 190, 0),
|
QColor(255, 190, 0),
|
||||||
QTextCharFormat::DotLine,
|
QTextCharFormat::DotLine,
|
||||||
FormatDescription::ShowUnderlineControl);
|
FormatDescription::ShowUnderlineControl);
|
||||||
|
formatDescr.emplace_back(C_OVERLOADED_OPERATOR,
|
||||||
|
tr("Overloaded Operators"),
|
||||||
|
tr("Calls and declarations of overloaded (user-defined) operators."),
|
||||||
|
Format::createMixinFormat());
|
||||||
Format declarationFormat = Format::createMixinFormat();
|
Format declarationFormat = Format::createMixinFormat();
|
||||||
declarationFormat.setBold(true);
|
declarationFormat.setBold(true);
|
||||||
formatDescr.emplace_back(C_DECLARATION,
|
formatDescr.emplace_back(C_DECLARATION,
|
||||||
|
@@ -91,6 +91,11 @@ public:
|
|||||||
return !isNull() && std::strlen(cString()) > 0;
|
return !isNull() && std::strlen(cString()) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool startsWith(const char* str) const
|
||||||
|
{
|
||||||
|
return std::strncmp(cString(), str, strlen(str)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
friend bool operator==(const ClangString &first, const ClangString &second)
|
friend bool operator==(const ClangString &first, const ClangString &second)
|
||||||
{
|
{
|
||||||
return std::strcmp(first.cString(), second.cString()) == 0;
|
return std::strcmp(first.cString(), second.cString()) == 0;
|
||||||
@@ -107,6 +112,7 @@ public:
|
|||||||
{
|
{
|
||||||
return second == first;
|
return second == first;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Type,
|
template<typename Type,
|
||||||
typename = typename std::enable_if<std::is_pointer<Type>::value>::type
|
typename = typename std::enable_if<std::is_pointer<Type>::value>::type
|
||||||
>
|
>
|
||||||
@@ -123,6 +129,39 @@ public:
|
|||||||
return second == first;
|
return second == first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(const ClangString &first, const ClangString &second)
|
||||||
|
{
|
||||||
|
return !(first == second);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t Size>
|
||||||
|
friend bool operator!=(const ClangString &first, const char(&second)[Size])
|
||||||
|
{
|
||||||
|
return !(first == second);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t Size>
|
||||||
|
friend bool operator!=(const char(&first)[Size], const ClangString &second)
|
||||||
|
{
|
||||||
|
return second != first;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Type,
|
||||||
|
typename = typename std::enable_if<std::is_pointer<Type>::value>::type
|
||||||
|
>
|
||||||
|
friend bool operator!=(const ClangString &first, Type second)
|
||||||
|
{
|
||||||
|
return !(first == second);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Type,
|
||||||
|
typename = typename std::enable_if<std::is_pointer<Type>::value>::type
|
||||||
|
>
|
||||||
|
friend bool operator!=(Type first, const ClangString &second)
|
||||||
|
{
|
||||||
|
return !(first == second);
|
||||||
|
}
|
||||||
|
|
||||||
friend std::ostream &operator<<(std::ostream &os, const ClangString &string)
|
friend std::ostream &operator<<(std::ostream &os, const ClangString &string)
|
||||||
{
|
{
|
||||||
return os << string.cString();
|
return os << string.cString();
|
||||||
|
@@ -216,16 +216,16 @@ void FullTokenInfo::memberReferenceKind(const Cursor &cursor)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FullTokenInfo::keywordKind(const Cursor &cursor)
|
void FullTokenInfo::keywordKind()
|
||||||
{
|
{
|
||||||
TokenInfo::keywordKind(cursor);
|
TokenInfo::keywordKind();
|
||||||
|
|
||||||
CXCursorKind cursorKind = cursor.kind();
|
CXCursorKind cursorKind = m_originalCursor.kind();
|
||||||
bool anonymous = false;
|
bool anonymous = false;
|
||||||
if (clang_Cursor_isAnonymous(cursor.cx())) {
|
if (clang_Cursor_isAnonymous(m_originalCursor.cx())) {
|
||||||
anonymous = true;
|
anonymous = true;
|
||||||
} else {
|
} else {
|
||||||
const Utf8String type = fullyQualifiedType(cursor);
|
const Utf8String type = fullyQualifiedType(m_originalCursor);
|
||||||
if (type.endsWith(Utf8StringLiteral(")"))
|
if (type.endsWith(Utf8StringLiteral(")"))
|
||||||
&& static_cast<const QByteArray &>(type).indexOf("(anonymous") >= 0) {
|
&& static_cast<const QByteArray &>(type).indexOf("(anonymous") >= 0) {
|
||||||
anonymous = true;
|
anonymous = true;
|
||||||
@@ -242,11 +242,33 @@ void FullTokenInfo::keywordKind(const Cursor &cursor)
|
|||||||
m_types.mixinHighlightingTypes.push_back(HighlightingType::Namespace);
|
m_types.mixinHighlightingTypes.push_back(HighlightingType::Namespace);
|
||||||
m_extraInfo.declaration = m_extraInfo.definition = true;
|
m_extraInfo.declaration = m_extraInfo.definition = true;
|
||||||
m_extraInfo.token = Utf8StringLiteral("anonymous");
|
m_extraInfo.token = Utf8StringLiteral("anonymous");
|
||||||
updateTypeSpelling(cursor);
|
updateTypeSpelling(m_originalCursor);
|
||||||
m_extraInfo.cursorRange = cursor.sourceRange();
|
m_extraInfo.cursorRange = m_originalCursor.sourceRange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FullTokenInfo::overloadedOperatorKind()
|
||||||
|
{
|
||||||
|
TokenInfo::overloadedOperatorKind();
|
||||||
|
|
||||||
|
if (m_types.mixinHighlightingTypes.front() != HighlightingType::OverloadedOperator)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Overloaded operator
|
||||||
|
m_extraInfo.identifier = true;
|
||||||
|
if (!m_originalCursor.isDeclaration())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Overloaded operator declaration
|
||||||
|
m_extraInfo.declaration = true;
|
||||||
|
m_extraInfo.definition = m_originalCursor.isDefinition();
|
||||||
|
|
||||||
|
updateTypeSpelling(m_originalCursor, true);
|
||||||
|
m_extraInfo.cursorRange = m_originalCursor.sourceRange();
|
||||||
|
m_extraInfo.accessSpecifier = m_originalCursor.accessSpecifier();
|
||||||
|
m_extraInfo.storageClass = m_originalCursor.storageClass();
|
||||||
|
}
|
||||||
|
|
||||||
void FullTokenInfo::evaluate()
|
void FullTokenInfo::evaluate()
|
||||||
{
|
{
|
||||||
m_extraInfo.token = ClangString(clang_getTokenSpelling(m_cxTranslationUnit, *m_cxToken));
|
m_extraInfo.token = ClangString(clang_getTokenSpelling(m_cxTranslationUnit, *m_cxToken));
|
||||||
|
@@ -48,7 +48,8 @@ protected:
|
|||||||
void variableKind(const Cursor &cursor) override;
|
void variableKind(const Cursor &cursor) override;
|
||||||
void fieldKind(const Cursor &cursor) override;
|
void fieldKind(const Cursor &cursor) override;
|
||||||
void memberReferenceKind(const Cursor &cursor) override;
|
void memberReferenceKind(const Cursor &cursor) override;
|
||||||
void keywordKind(const Cursor &cursor) override;
|
void keywordKind() override;
|
||||||
|
void overloadedOperatorKind() override;
|
||||||
private:
|
private:
|
||||||
void updateTypeSpelling(const Cursor &cursor, bool functionLike = false);
|
void updateTypeSpelling(const Cursor &cursor, bool functionLike = false);
|
||||||
void updatePropertyData();
|
void updatePropertyData();
|
||||||
|
@@ -98,9 +98,7 @@ TokenInfo::operator TokenInfoContainer() const
|
|||||||
return TokenInfoContainer(m_line, m_column, m_length, m_types);
|
return TokenInfoContainer(m_line, m_column, m_length, m_types);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
static bool isFinalFunction(const Cursor &cursor)
|
||||||
|
|
||||||
bool isFinalFunction(const Cursor &cursor)
|
|
||||||
{
|
{
|
||||||
auto referencedCursor = cursor.referenced();
|
auto referencedCursor = cursor.referenced();
|
||||||
if (referencedCursor.hasFinalFunctionAttribute())
|
if (referencedCursor.hasFinalFunctionAttribute())
|
||||||
@@ -109,7 +107,7 @@ bool isFinalFunction(const Cursor &cursor)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isFunctionInFinalClass(const Cursor &cursor)
|
static bool isFunctionInFinalClass(const Cursor &cursor)
|
||||||
{
|
{
|
||||||
auto functionBase = cursor.functionBaseDeclaration();
|
auto functionBase = cursor.functionBaseDeclaration();
|
||||||
if (functionBase.isValid() && functionBase.hasFinalClassAttribute())
|
if (functionBase.isValid() && functionBase.hasFinalClassAttribute())
|
||||||
@@ -117,7 +115,6 @@ bool isFunctionInFinalClass(const Cursor &cursor)
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void TokenInfo::memberReferenceKind(const Cursor &cursor)
|
void TokenInfo::memberReferenceKind(const Cursor &cursor)
|
||||||
{
|
{
|
||||||
@@ -196,12 +193,11 @@ bool TokenInfo::isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) con
|
|||||||
&& (m_originalCursor.isDeclaration() || m_originalCursor.isDefinition());
|
&& (m_originalCursor.isDeclaration() || m_originalCursor.isDefinition());
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
static bool isNotFinalFunction(const Cursor &cursor)
|
||||||
bool isNotFinalFunction(const Cursor &cursor)
|
|
||||||
{
|
{
|
||||||
return !cursor.hasFinalFunctionAttribute();
|
return !cursor.hasFinalFunctionAttribute();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
bool TokenInfo::isRealDynamicCall(const Cursor &cursor) const
|
bool TokenInfo::isRealDynamicCall(const Cursor &cursor) const
|
||||||
{
|
{
|
||||||
return m_originalCursor.isDynamicCall() && isNotFinalFunction(cursor);
|
return m_originalCursor.isDynamicCall() && isNotFinalFunction(cursor);
|
||||||
@@ -246,9 +242,7 @@ void TokenInfo::collectOutputArguments(const Cursor &cursor)
|
|||||||
filterOutPreviousOutputArguments();
|
filterOutPreviousOutputArguments();
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
static uint getEnd(CXSourceRange cxSourceRange)
|
||||||
|
|
||||||
uint getEnd(CXSourceRange cxSourceRange)
|
|
||||||
{
|
{
|
||||||
CXSourceLocation startSourceLocation = clang_getRangeEnd(cxSourceRange);
|
CXSourceLocation startSourceLocation = clang_getRangeEnd(cxSourceRange);
|
||||||
|
|
||||||
@@ -258,7 +252,6 @@ uint getEnd(CXSourceRange cxSourceRange)
|
|||||||
|
|
||||||
return endOffset;
|
return endOffset;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void TokenInfo::filterOutPreviousOutputArguments()
|
void TokenInfo::filterOutPreviousOutputArguments()
|
||||||
{
|
{
|
||||||
@@ -456,8 +449,7 @@ void TokenInfo::identifierKind(const Cursor &cursor, Recursion recursion)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
static HighlightingType literalKind(const Cursor &cursor)
|
||||||
HighlightingType literalKind(const Cursor &cursor)
|
|
||||||
{
|
{
|
||||||
switch (cursor.kind()) {
|
switch (cursor.kind()) {
|
||||||
case CXCursor_CharacterLiteral:
|
case CXCursor_CharacterLiteral:
|
||||||
@@ -476,32 +468,86 @@ HighlightingType literalKind(const Cursor &cursor)
|
|||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasOperatorName(const char *operatorString)
|
static bool isTokenPartOfOperator(const Cursor &declarationCursor, CXToken *token)
|
||||||
{
|
{
|
||||||
return std::strncmp(operatorString, "operator", 8) == 0;
|
Q_ASSERT(declarationCursor.isDeclaration());
|
||||||
|
const CXTranslationUnit cxTranslationUnit = declarationCursor.cxTranslationUnit();
|
||||||
|
const ClangString tokenName = clang_getTokenSpelling(cxTranslationUnit, *token);
|
||||||
|
if (tokenName == "operator")
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (tokenName == "(") {
|
||||||
|
// Valid operator declarations have at least one token after '(' so
|
||||||
|
// it's safe to proceed to token + 1 without extra checks.
|
||||||
|
const ClangString nextToken = clang_getTokenSpelling(cxTranslationUnit, *(token + 1));
|
||||||
|
if (nextToken != ")") {
|
||||||
|
// Argument lists' parentheses are not operator tokens.
|
||||||
|
// This '('-token opens a (non-empty) argument list.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's safe to evaluate the preceding token because we will at least have
|
||||||
|
// the 'operator'-keyword's token to the left.
|
||||||
|
CXToken *prevToken = token - 1;
|
||||||
|
if (clang_getTokenKind(*prevToken) == CXToken_Punctuation) {
|
||||||
|
if (tokenName == "(") {
|
||||||
|
// In an operator declaration, when a '(' follows another punctuation
|
||||||
|
// then this '(' opens an argument list. Ex: operator*()|operator()().
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This token is preceded by another punctuation token so this token
|
||||||
|
// could be the second token of a two-tokened operator such as
|
||||||
|
// operator+=|-=|*=|/=|<<|==|<=|++ or the third token of operator
|
||||||
|
// new[]|delete[]. We decrement one more time to hit one of the keywords:
|
||||||
|
// "operator" / "delete" / "new".
|
||||||
|
--prevToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ClangString precedingKeyword =
|
||||||
|
clang_getTokenSpelling(cxTranslationUnit, *prevToken);
|
||||||
|
|
||||||
|
return precedingKeyword == "operator" ||
|
||||||
|
precedingKeyword == "new" ||
|
||||||
|
precedingKeyword == "delete";
|
||||||
}
|
}
|
||||||
|
|
||||||
HighlightingType operatorKind(const Cursor &cursor)
|
void TokenInfo::overloadedOperatorKind()
|
||||||
{
|
{
|
||||||
if (hasOperatorName(cursor.spelling().cString()))
|
bool inOperatorDeclaration = m_originalCursor.isDeclaration();
|
||||||
return HighlightingType::Operator;
|
Cursor declarationCursor =
|
||||||
else
|
inOperatorDeclaration ? m_originalCursor :
|
||||||
return HighlightingType::Invalid;
|
m_originalCursor.referenced();
|
||||||
|
if (!declarationCursor.displayName().startsWith("operator"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (inOperatorDeclaration && !isTokenPartOfOperator(declarationCursor, m_cxToken))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_types.mainHighlightingType == HighlightingType::Invalid)
|
||||||
|
m_types.mainHighlightingType = HighlightingType::Operator;
|
||||||
|
m_types.mixinHighlightingTypes.push_back(HighlightingType::OverloadedOperator);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
void TokenInfo::punctuationOrOperatorKind()
|
||||||
|
|
||||||
HighlightingType TokenInfo::punctuationKind(const Cursor &cursor)
|
|
||||||
{
|
{
|
||||||
HighlightingType highlightingType = HighlightingType::Invalid;
|
auto kind = m_originalCursor.kind();
|
||||||
|
switch (kind) {
|
||||||
switch (cursor.kind()) {
|
case CXCursor_CallExpr:
|
||||||
|
collectOutputArguments(m_originalCursor);
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case CXCursor_FunctionDecl:
|
||||||
|
case CXCursor_CXXMethod:
|
||||||
case CXCursor_DeclRefExpr:
|
case CXCursor_DeclRefExpr:
|
||||||
highlightingType = operatorKind(cursor);
|
// TODO(QTCREATORBUG-19948): Mark calls to overloaded new and delete.
|
||||||
|
// Today we can't because libclang sets these cursors' spelling to "".
|
||||||
|
// case CXCursor_CXXNewExpr:
|
||||||
|
// case CXCursor_CXXDeleteExpr:
|
||||||
|
overloadedOperatorKind();
|
||||||
break;
|
break;
|
||||||
case CXCursor_Constructor:
|
case CXCursor_Constructor:
|
||||||
case CXCursor_CallExpr:
|
collectOutputArguments(m_originalCursor);
|
||||||
collectOutputArguments(cursor);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -509,8 +555,6 @@ HighlightingType TokenInfo::punctuationKind(const Cursor &cursor)
|
|||||||
|
|
||||||
if (isOutputArgument())
|
if (isOutputArgument())
|
||||||
m_types.mixinHighlightingTypes.push_back(HighlightingType::OutputArgument);
|
m_types.mixinHighlightingTypes.push_back(HighlightingType::OutputArgument);
|
||||||
|
|
||||||
return highlightingType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class PropertyPart
|
enum class PropertyPart
|
||||||
@@ -582,17 +626,20 @@ void TokenInfo::invalidFileKind()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static HighlightingType highlightingTypeForKeyword(CXTranslationUnit cxTranslationUnit,
|
void TokenInfo::keywordKind()
|
||||||
CXToken *cxToken,
|
|
||||||
const Cursor &cursor)
|
|
||||||
{
|
{
|
||||||
switch (cursor.kind()) {
|
switch (m_originalCursor.kind()) {
|
||||||
case CXCursor_PreprocessingDirective: return HighlightingType::Preprocessor;
|
case CXCursor_PreprocessingDirective:
|
||||||
case CXCursor_InclusionDirective: return HighlightingType::StringLiteral;
|
m_types.mainHighlightingType = HighlightingType::Preprocessor;
|
||||||
default: break;
|
return;
|
||||||
|
case CXCursor_InclusionDirective:
|
||||||
|
m_types.mainHighlightingType = HighlightingType::StringLiteral;
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ClangString spelling = clang_getTokenSpelling(cxTranslationUnit, *cxToken);
|
const ClangString spelling = clang_getTokenSpelling(m_cxTranslationUnit, *m_cxToken);
|
||||||
if (spelling == "bool"
|
if (spelling == "bool"
|
||||||
|| spelling == "char"
|
|| spelling == "char"
|
||||||
|| spelling == "char16_t"
|
|| spelling == "char16_t"
|
||||||
@@ -606,17 +653,14 @@ static HighlightingType highlightingTypeForKeyword(CXTranslationUnit cxTranslati
|
|||||||
|| spelling == "unsigned"
|
|| spelling == "unsigned"
|
||||||
|| spelling == "void"
|
|| spelling == "void"
|
||||||
|| spelling == "wchar_t") {
|
|| spelling == "wchar_t") {
|
||||||
return HighlightingType::PrimitiveType;
|
m_types.mainHighlightingType = HighlightingType::PrimitiveType;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return HighlightingType::Keyword;
|
m_types.mainHighlightingType = HighlightingType::Keyword;
|
||||||
}
|
|
||||||
|
|
||||||
void TokenInfo::keywordKind(const Cursor &cursor)
|
if (spelling == "new" || spelling == "delete" || spelling == "operator")
|
||||||
{
|
overloadedOperatorKind();
|
||||||
m_types.mainHighlightingType = highlightingTypeForKeyword(m_cxTranslationUnit,
|
|
||||||
m_cxToken,
|
|
||||||
cursor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TokenInfo::evaluate()
|
void TokenInfo::evaluate()
|
||||||
@@ -627,10 +671,10 @@ void TokenInfo::evaluate()
|
|||||||
|
|
||||||
switch (cxTokenKind) {
|
switch (cxTokenKind) {
|
||||||
case CXToken_Keyword:
|
case CXToken_Keyword:
|
||||||
keywordKind(m_originalCursor);
|
keywordKind();
|
||||||
break;
|
break;
|
||||||
case CXToken_Punctuation:
|
case CXToken_Punctuation:
|
||||||
m_types.mainHighlightingType = punctuationKind(m_originalCursor);
|
punctuationOrOperatorKind();
|
||||||
break;
|
break;
|
||||||
case CXToken_Identifier:
|
case CXToken_Identifier:
|
||||||
identifierKind(m_originalCursor, Recursion::FirstPass);
|
identifierKind(m_originalCursor, Recursion::FirstPass);
|
||||||
|
@@ -93,10 +93,11 @@ protected:
|
|||||||
virtual void fieldKind(const Cursor &cursor);
|
virtual void fieldKind(const Cursor &cursor);
|
||||||
virtual void functionKind(const Cursor &cursor, Recursion recursion);
|
virtual void functionKind(const Cursor &cursor, Recursion recursion);
|
||||||
virtual void memberReferenceKind(const Cursor &cursor);
|
virtual void memberReferenceKind(const Cursor &cursor);
|
||||||
virtual HighlightingType punctuationKind(const Cursor &cursor);
|
|
||||||
virtual void typeKind(const Cursor &cursor);
|
virtual void typeKind(const Cursor &cursor);
|
||||||
virtual void keywordKind(const Cursor &cursor);
|
virtual void keywordKind();
|
||||||
virtual void invalidFileKind();
|
virtual void invalidFileKind();
|
||||||
|
virtual void overloadedOperatorKind();
|
||||||
|
virtual void punctuationOrOperatorKind();
|
||||||
|
|
||||||
Cursor m_originalCursor;
|
Cursor m_originalCursor;
|
||||||
CXToken *m_cxToken = nullptr;
|
CXToken *m_cxToken = nullptr;
|
||||||
|
@@ -105,9 +105,9 @@ TEST(ClangString, NotEqualBetweenClangStrings)
|
|||||||
ClangString text(CXString{"text", 0});
|
ClangString text(CXString{"text", 0});
|
||||||
ClangString text2(CXString{"text ", 0});
|
ClangString text2(CXString{"text ", 0});
|
||||||
|
|
||||||
bool textIsEqual = text == text2;
|
bool textIsNotEqual = text != text2;
|
||||||
|
|
||||||
ASSERT_FALSE(textIsEqual);
|
ASSERT_TRUE(textIsNotEqual);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ClangString, EqualClangStringAndCString)
|
TEST(ClangString, EqualClangStringAndCString)
|
||||||
@@ -123,9 +123,9 @@ TEST(ClangString, NotEqualClangStringAndCString)
|
|||||||
{
|
{
|
||||||
ClangString text(CXString{"text", 0});
|
ClangString text(CXString{"text", 0});
|
||||||
|
|
||||||
bool textIsEqual = text == "text ";
|
bool textIsNotEqual = text != "text ";
|
||||||
|
|
||||||
ASSERT_FALSE(textIsEqual);
|
ASSERT_TRUE(textIsNotEqual);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ClangString, EqualCStringAndClangString)
|
TEST(ClangString, EqualCStringAndClangString)
|
||||||
@@ -137,6 +137,15 @@ TEST(ClangString, EqualCStringAndClangString)
|
|||||||
ASSERT_TRUE(textIsEqual);
|
ASSERT_TRUE(textIsEqual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ClangString, NotEqualCStringAndClangString)
|
||||||
|
{
|
||||||
|
ClangString text(CXString{"text", 0});
|
||||||
|
|
||||||
|
bool textIsNotEqual = "text " != text;
|
||||||
|
|
||||||
|
ASSERT_TRUE(textIsNotEqual);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ClangString, EqualClangStringPointerAndCString)
|
TEST(ClangString, EqualClangStringPointerAndCString)
|
||||||
{
|
{
|
||||||
ClangString text(CXString{"text", 0});
|
ClangString text(CXString{"text", 0});
|
||||||
@@ -152,9 +161,9 @@ TEST(ClangString, NotEqualClangStringPointerAndCString)
|
|||||||
ClangString text(CXString{"text", 0});
|
ClangString text(CXString{"text", 0});
|
||||||
const char *cString = "text ";
|
const char *cString = "text ";
|
||||||
|
|
||||||
bool textIsEqual = cString == text;
|
bool textIsNotEqual = cString != text;
|
||||||
|
|
||||||
ASSERT_FALSE(textIsEqual);
|
ASSERT_TRUE(textIsNotEqual);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ClangString, EqualCStringAndClangStringPointer)
|
TEST(ClangString, EqualCStringAndClangStringPointer)
|
||||||
@@ -167,6 +176,16 @@ TEST(ClangString, EqualCStringAndClangStringPointer)
|
|||||||
ASSERT_TRUE(textIsEqual);
|
ASSERT_TRUE(textIsEqual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ClangString, NotEqualCStringAndClangStringPointer)
|
||||||
|
{
|
||||||
|
ClangString text(CXString{"text", 0});
|
||||||
|
const char *cString = "text ";
|
||||||
|
|
||||||
|
bool textIsNotEqual = text != cString;
|
||||||
|
|
||||||
|
ASSERT_TRUE(textIsNotEqual);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ClangString, NullStringHasNoContent)
|
TEST(ClangString, NullStringHasNoContent)
|
||||||
{
|
{
|
||||||
ClangString text(CXString{nullptr, 0});
|
ClangString text(CXString{nullptr, 0});
|
||||||
|
@@ -600,6 +600,44 @@ class Property {
|
|||||||
Q_PROPERTY(const QString str READ getStr)
|
Q_PROPERTY(const QString str READ getStr)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct X {
|
||||||
|
void operator*(int) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
void operator*(X, float) {}
|
||||||
|
|
||||||
|
void CallSite() {
|
||||||
|
X x;
|
||||||
|
int y = 10;
|
||||||
|
float z = 10;
|
||||||
|
x * y;
|
||||||
|
x * z;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Dummy {
|
||||||
|
Dummy operator<<=(int key);
|
||||||
|
Dummy operator()(int a);
|
||||||
|
int& operator[] (unsigned index);
|
||||||
|
void* operator new(unsigned size);
|
||||||
|
void operator delete(void* ptr);
|
||||||
|
void* operator new[](unsigned size);
|
||||||
|
void operator delete[](void* ptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
void TryOverloadedOperators(Dummy object)
|
||||||
|
{
|
||||||
|
object <<= 3;
|
||||||
|
|
||||||
|
Dummy stacked;
|
||||||
|
stacked(4);
|
||||||
|
stacked[1];
|
||||||
|
int *i = new int;
|
||||||
|
Dummy* use_new = new Dummy();
|
||||||
|
delete use_new;
|
||||||
|
Dummy* many = new Dummy[10];
|
||||||
|
delete [] many;
|
||||||
|
}
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
Test = 0
|
Test = 0
|
||||||
};
|
};
|
||||||
@@ -611,3 +649,17 @@ class B {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Dummy2 {
|
||||||
|
Dummy2 operator()();
|
||||||
|
int operator*();
|
||||||
|
Dummy2 operator=(int foo);
|
||||||
|
};
|
||||||
|
|
||||||
|
void TryOverloadedOperators2(Dummy object)
|
||||||
|
{
|
||||||
|
Dummy2 dummy2;
|
||||||
|
dummy2();
|
||||||
|
*dummy2;
|
||||||
|
dummy2 = 3;
|
||||||
|
}
|
||||||
|
@@ -584,18 +584,270 @@ TEST_F(TokenProcessor, NonFinalVirtualFunctionCallPointer)
|
|||||||
ASSERT_THAT(infos[2], HasOnlyType(HighlightingType::VirtualFunction));
|
ASSERT_THAT(infos[2], HasOnlyType(HighlightingType::VirtualFunction));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TokenProcessor, PlusOperator)
|
TEST_F(TokenProcessor, OverriddenPlusOperatorDeclaration)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(220, 67));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[2], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, CallToOverriddenPlusOperator)
|
||||||
{
|
{
|
||||||
const auto infos = translationUnit.tokenInfosInRange(sourceRange(224, 49));
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(224, 49));
|
||||||
|
|
||||||
ASSERT_THAT(infos[6], HasOnlyType(HighlightingType::Operator));
|
ASSERT_THAT(infos[6], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TokenProcessor, PlusAssignOperator)
|
TEST_F(TokenProcessor, CallToOverriddenPlusAssignOperator)
|
||||||
{
|
{
|
||||||
const auto infos = translationUnit.tokenInfosInRange(sourceRange(226, 24));
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(226, 24));
|
||||||
|
|
||||||
ASSERT_THAT(infos[1], HasOnlyType(HighlightingType::Operator));
|
ASSERT_THAT(infos[1], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, OverriddenStarOperatorMemberDefinition)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(604, 26));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[2], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, OverriddenStarOperatorNonMemberDefinition)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(607, 29));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[2], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, IntegerCallToOverriddenBinaryOperator)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(613, 9));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[1], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, FloatCallToOverriddenBinaryOperator)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(614, 9));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[1], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, LeftShiftAssignmentOperatorMemberDefinition)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(618, 32));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[2], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator));
|
||||||
|
ASSERT_THAT(infos[3], HasOnlyType(HighlightingType::Invalid)); // ( is a punctuation.
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, CalledLeftShiftAssignmentOperator)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(629, 18));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[1], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator));
|
||||||
|
ASSERT_THAT(infos[2], HasOnlyType(HighlightingType::NumberLiteral));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, FunctionCallOperatorMemberDefinition)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(619, 29));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[2], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator));
|
||||||
|
ASSERT_THAT(infos[3], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator));
|
||||||
|
ASSERT_THAT(infos[4], HasOnlyType(HighlightingType::Invalid)); // ( is a punctuation.
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, CalledFunctionCallOperator)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(632, 16));
|
||||||
|
ASSERT_THAT(infos[1], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator));
|
||||||
|
ASSERT_THAT(infos[3], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, AccessOperatorMemberDefinition)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(620, 38));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[3], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator));
|
||||||
|
ASSERT_THAT(infos[4], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator));
|
||||||
|
ASSERT_THAT(infos[5], HasOnlyType(HighlightingType::Invalid)); // ( is a punctuation.
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, CalledAccessOperator)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(633, 16));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[1], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator));
|
||||||
|
ASSERT_THAT(infos[3], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, NewOperatorMemberDefinition)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(621, 39));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[3], HasTwoTypes(HighlightingType::Keyword, HighlightingType::OverloadedOperator));
|
||||||
|
ASSERT_THAT(infos[4], HasOnlyType(HighlightingType::Invalid)); // ( is a punctuation.
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, CalledNewOperator)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(635, 34));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[3], HasOnlyType(HighlightingType::Invalid)); // = is not marked.
|
||||||
|
// CLANG-UPGRADE-CHECK: Check if 'new' keyword usage cursor correctly returns referenced() cursor
|
||||||
|
// and uncomment this test in that case.
|
||||||
|
// ASSERT_THAT(infos[4], HasTwoTypes(HighlightingType::Keyword, HighlightingType::OverloadedOperator)); // new
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, DeleteOperatorMemberDefinition)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(622, 37));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[2], HasTwoTypes(HighlightingType::Keyword, HighlightingType::OverloadedOperator)); // delete
|
||||||
|
ASSERT_THAT(infos[3], HasOnlyType(HighlightingType::Invalid)); // ( is a punctuation.
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, CalledDeleteOperator)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(636, 20));
|
||||||
|
|
||||||
|
// CLANG-UPGRADE-CHECK: Check if 'delete' keyword usage cursor correctly returns referenced() cursor
|
||||||
|
// and uncomment this test in that case.
|
||||||
|
// ASSERT_THAT(infos[0], HasTwoTypes(HighlightingType::Keyword, HighlightingType::OverloadedOperator)); // delete
|
||||||
|
ASSERT_THAT(infos[1], HasOnlyType(HighlightingType::LocalVariable));
|
||||||
|
ASSERT_THAT(infos[2], HasOnlyType(HighlightingType::Invalid)); // ; is a punctuation.
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, NewArrayOperatorMemberDefinition)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(623, 41));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[3], HasTwoTypes(HighlightingType::Keyword, HighlightingType::OverloadedOperator)); // new
|
||||||
|
ASSERT_THAT(infos[4], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator)); // [
|
||||||
|
ASSERT_THAT(infos[5], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator)); // ]
|
||||||
|
ASSERT_THAT(infos[6], HasOnlyType(HighlightingType::Invalid)); // ( is a punctuation.
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, CalledNewArrayOperator)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(637, 34));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[3], HasOnlyType(HighlightingType::Invalid)); // = is not marked.
|
||||||
|
// CLANG-UPGRADE-CHECK: Check if 'new' keyword usage cursor correctly returns referenced() cursor
|
||||||
|
// and uncomment this test in that case.
|
||||||
|
// ASSERT_THAT(infos[4], HasTwoTypes(HighlightingType::Keyword, HighlightingType::OverloadedOperator)); // new
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, DeleteArrayOperatorMemberDefinition)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(624, 39));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[2], HasTwoTypes(HighlightingType::Keyword, HighlightingType::OverloadedOperator)); // delete
|
||||||
|
ASSERT_THAT(infos[3], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator)); // [
|
||||||
|
ASSERT_THAT(infos[4], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator)); // ]
|
||||||
|
ASSERT_THAT(infos[5], HasOnlyType(HighlightingType::Invalid)); // ( is a punctuation.
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, CalledDeleteArrayOperator)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(638, 20));
|
||||||
|
|
||||||
|
// CLANG-UPGRADE-CHECK: Check if 'delete' keyword usage cursor correctly returns referenced() cursor
|
||||||
|
// and uncomment this test in that case.
|
||||||
|
// ASSERT_THAT(infos[0], HasTwoTypes(HighlightingType::Keyword, HighlightingType::OverloadedOperator)); // delete
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, CalledNotOverloadedOperator)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(634, 22));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[4], HasOnlyType(HighlightingType::Keyword)); // new
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, ParenthesisOperatorWithoutArguments)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(654, 25));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[1], HasTwoTypes(HighlightingType::Keyword, HighlightingType::OverloadedOperator)); // operator
|
||||||
|
ASSERT_THAT(infos[2], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator)); // '('
|
||||||
|
ASSERT_THAT(infos[3], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator)); // ')'
|
||||||
|
ASSERT_THAT(infos[4], HasOnlyType(HighlightingType::Invalid)); // second '(' is a punctuation
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, CalledParenthesisOperatorWithoutArguments)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(662, 14));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[1], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator)); // '('
|
||||||
|
ASSERT_THAT(infos[2], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator)); // ')'
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, OperatorWithOnePunctuationTokenWithoutArguments)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(655, 25));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[1], HasTwoTypes(HighlightingType::Keyword, HighlightingType::OverloadedOperator)); // operator
|
||||||
|
ASSERT_THAT(infos[2], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator)); // '*'
|
||||||
|
ASSERT_THAT(infos[3], HasOnlyType(HighlightingType::Invalid)); // ( is a punctuation
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, CalledOperatorWithOnePunctuationTokenWithoutArguments)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(663, 13));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[0], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator)); // '*'
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, EqualsOperatorOverload)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(656, 43));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[1], HasTwoTypes(HighlightingType::Keyword, HighlightingType::OverloadedOperator)); // operator
|
||||||
|
ASSERT_THAT(infos[2], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator)); // '='
|
||||||
|
ASSERT_THAT(infos[3], HasOnlyType(HighlightingType::Invalid)); // ( is a punctuation
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, CalledEqualsOperatorOverload)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(664, 23));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[1], HasTwoTypes(HighlightingType::Operator, HighlightingType::OverloadedOperator)); // '='
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, LeftParenthesisIsAPunctuation)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(607, 29));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[3], HasOnlyType(HighlightingType::Invalid));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, SeparatingCommaIsAPunctuation)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(607, 29));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[5], HasOnlyType(HighlightingType::Invalid));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, RightParenthesisIsAPunctuation)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(607, 29));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[7], HasOnlyType(HighlightingType::Invalid));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, CurlyLeftParenthesisIsAPunctuation)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(607, 29));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[8], HasOnlyType(HighlightingType::Invalid));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TokenProcessor, CurlyRightParenthesisIsAPunctuation)
|
||||||
|
{
|
||||||
|
const auto infos = translationUnit.tokenInfosInRange(sourceRange(607, 29));
|
||||||
|
|
||||||
|
ASSERT_THAT(infos[9], HasOnlyType(HighlightingType::Invalid));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TokenProcessor, Comment)
|
TEST_F(TokenProcessor, Comment)
|
||||||
@@ -1326,7 +1578,7 @@ TEST_F(TokenProcessor, CursorRange)
|
|||||||
|
|
||||||
TEST_F(TokenProcessor, AnonymousEnum)
|
TEST_F(TokenProcessor, AnonymousEnum)
|
||||||
{
|
{
|
||||||
const auto infos = translationUnit.fullTokenInfosInRange(sourceRange(603, 7));
|
const auto infos = translationUnit.fullTokenInfosInRange(sourceRange(641, 7));
|
||||||
|
|
||||||
ClangBackEnd::TokenInfoContainer container(infos[0]);
|
ClangBackEnd::TokenInfoContainer container(infos[0]);
|
||||||
|
|
||||||
@@ -1336,7 +1588,7 @@ TEST_F(TokenProcessor, AnonymousEnum)
|
|||||||
|
|
||||||
TEST_F(TokenProcessor, AnonymousNamespace)
|
TEST_F(TokenProcessor, AnonymousNamespace)
|
||||||
{
|
{
|
||||||
const auto infos = translationUnit.fullTokenInfosInRange(sourceRange(607, 12));
|
const auto infos = translationUnit.fullTokenInfosInRange(sourceRange(645, 12));
|
||||||
|
|
||||||
ClangBackEnd::TokenInfoContainer container(infos[0]);
|
ClangBackEnd::TokenInfoContainer container(infos[0]);
|
||||||
|
|
||||||
@@ -1346,7 +1598,7 @@ TEST_F(TokenProcessor, AnonymousNamespace)
|
|||||||
|
|
||||||
TEST_F(TokenProcessor, AnonymousStruct)
|
TEST_F(TokenProcessor, AnonymousStruct)
|
||||||
{
|
{
|
||||||
const auto infos = translationUnit.fullTokenInfosInRange(sourceRange(609, 13));
|
const auto infos = translationUnit.fullTokenInfosInRange(sourceRange(647, 13));
|
||||||
|
|
||||||
ClangBackEnd::TokenInfoContainer container(infos[0]);
|
ClangBackEnd::TokenInfoContainer container(infos[0]);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user