Clang: Add output argument highlighting

This adds a mix-in for writable functions arguments.

Change-Id: I758f7fef77d992ea25395db550571ccb081fd5fd
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
This commit is contained in:
Marco Bubke
2016-10-11 18:19:12 +02:00
committed by Nikolai Kosjar
parent 9d55d8485c
commit 63ae993bf2
18 changed files with 447 additions and 57 deletions

View File

@@ -60,6 +60,8 @@ TextEditor::TextStyle toTextStyle(ClangBackEnd::HighlightingType type)
return TextEditor::C_PREPROCESSOR; return TextEditor::C_PREPROCESSOR;
case HighlightingType::Declaration: case HighlightingType::Declaration:
return TextEditor::C_DECLARATION; return TextEditor::C_DECLARATION;
case HighlightingType::OutputArgument:
return TextEditor::C_OUTPUT_ARGUMENT;
default: default:
return TextEditor::C_TEXT; // never called return TextEditor::C_TEXT; // never called
} }

View File

@@ -102,6 +102,7 @@ const char *nameForStyle(TextStyle style)
case C_WARNING_CONTEXT: return "WarningContext"; case C_WARNING_CONTEXT: return "WarningContext";
case C_DECLARATION: return "Declaration"; case C_DECLARATION: return "Declaration";
case C_OUTPUT_ARGUMENT: return "C_OUTPUT_ARGUMENT";
case C_LAST_STYLE_SENTINEL: return "LastStyleSentinel"; case C_LAST_STYLE_SENTINEL: return "LastStyleSentinel";
} }

View File

@@ -100,6 +100,7 @@ enum TextStyle : quint8 {
C_ERROR_CONTEXT, C_ERROR_CONTEXT,
C_DECLARATION, C_DECLARATION,
C_OUTPUT_ARGUMENT,
C_LAST_STYLE_SENTINEL C_LAST_STYLE_SENTINEL
}; };

View File

@@ -313,6 +313,10 @@ TextEditorSettings::TextEditorSettings(QObject *parent)
tr("Declaration"), tr("Declaration"),
tr("Declaration of a function, variable, and so on."), tr("Declaration of a function, variable, and so on."),
FormatDescription::ShowFontUnderlineAndRelativeControls); FormatDescription::ShowFontUnderlineAndRelativeControls);
formatDescr.emplace_back(C_OUTPUT_ARGUMENT,
tr("Output Argument"),
tr("Writable arguments of a function call."),
FormatDescription::ShowFontUnderlineAndRelativeControls);
d->m_fontSettingsPage = new FontSettingsPage(formatDescr, d->m_fontSettingsPage = new FontSettingsPage(formatDescr,
Constants::TEXT_EDITOR_FONT_SETTINGS, Constants::TEXT_EDITOR_FONT_SETTINGS,

View File

@@ -69,7 +69,7 @@ bool Type::isReferencingConstant() const
return (isPointer() || isLValueReference()) && pointeeType().isConstant(); return (isPointer() || isLValueReference()) && pointeeType().isConstant();
} }
bool Type::isOutputParameter() const bool Type::isOutputArgument() const
{ {
return (isPointer() || isLValueReference()) && !pointeeType().isConstant(); return (isPointer() || isLValueReference()) && !pointeeType().isConstant();
} }

View File

@@ -49,7 +49,7 @@ public:
bool isConstantPointer() const; bool isConstantPointer() const;
bool isLValueReference() const; bool isLValueReference() const;
bool isReferencingConstant() const; bool isReferencingConstant() const;
bool isOutputParameter() const; bool isOutputArgument() const;
Utf8String utf8Spelling() const; Utf8String utf8Spelling() const;
ClangString spelling() const; ClangString spelling() const;

View File

@@ -213,16 +213,32 @@ SourceLocation Cursor::sourceLocation() const
return clang_getCursorLocation(cxCursor); return clang_getCursorLocation(cxCursor);
} }
CXSourceLocation Cursor::cxSourceLocation() const
{
return clang_getCursorLocation(cxCursor);
}
SourceRange Cursor::sourceRange() const SourceRange Cursor::sourceRange() const
{ {
return clang_getCursorExtent(cxCursor); return clang_getCursorExtent(cxCursor);
} }
CXSourceRange Cursor::cxSourceRange() const
{
return clang_getCursorExtent(cxCursor);
}
SourceRange Cursor::commentRange() const SourceRange Cursor::commentRange() const
{ {
return clang_Cursor_getCommentRange(cxCursor); return clang_Cursor_getCommentRange(cxCursor);
} }
bool Cursor::hasSameSourceLocationAs(const Cursor &other) const
{
return clang_equalLocations(clang_getCursorLocation(cxCursor),
clang_getCursorLocation(other.cxCursor));
}
Cursor Cursor::definition() const Cursor Cursor::definition() const
{ {
return clang_getCursorDefinition(cxCursor); return clang_getCursorDefinition(cxCursor);
@@ -279,32 +295,42 @@ Cursor Cursor::argument(int index) const
{ {
return clang_Cursor_getArgument(cxCursor, index); return clang_Cursor_getArgument(cxCursor, index);
} }
namespace { namespace {
void collectOutputArguments(const Cursor &callExpression,
std::vector<Cursor> &outputArguments) bool isNotUnexposedLValueReference(const Cursor &argument, const Type &argumentType)
{ {
auto callExpressionType = callExpression.referenced().type(); return !(argument.isUnexposed() && argumentType.isLValueReference());
auto argumentCount = callExpression.argumentCount(); }
outputArguments.reserve(argumentCount);
}
void Cursor::collectOutputArgumentRangesTo(std::vector<CXSourceRange> &outputArgumentRanges) const
{
const Type callExpressionType = referenced().type();
const int argumentCount = this->argumentCount();
const std::size_t maxSize = std::size_t(std::max(0, argumentCount))
+ outputArgumentRanges.size();
outputArgumentRanges.reserve(maxSize);
for (int argumentIndex = 0; argumentIndex < argumentCount; ++argumentIndex) { for (int argumentIndex = 0; argumentIndex < argumentCount; ++argumentIndex) {
auto argument = callExpression.argument(argumentIndex); const Cursor argument = this->argument(argumentIndex);
auto argumentType = callExpressionType.argument(argumentIndex); const Type argumentType = callExpressionType.argument(argumentIndex);
if (!argument.isUnexposed() && argumentType.isOutputParameter()) if (isNotUnexposedLValueReference(argument, argumentType)
outputArguments.push_back(callExpression.argument(argumentIndex)); && argumentType.isOutputArgument()) {
outputArgumentRanges.push_back(argument.cxSourceRange());
}
} }
} }
}
std::vector<Cursor> Cursor::outputArguments() const std::vector<CXSourceRange> Cursor::outputArgumentRanges() const
{ {
std::vector<Cursor> outputArguments; std::vector<CXSourceRange> outputArgumentRanges;
if (kind() == CXCursor_CallExpr) collectOutputArgumentRangesTo(outputArgumentRanges);
collectOutputArguments(*this, outputArguments);
return outputArguments; return outputArgumentRanges;
} }
CXCursorKind Cursor::kind() const CXCursorKind Cursor::kind() const
@@ -317,6 +343,11 @@ bool operator==(const Cursor &first, const Cursor &second)
return clang_equalCursors(first.cxCursor, second.cxCursor); return clang_equalCursors(first.cxCursor, second.cxCursor);
} }
bool operator!=(const Cursor &first, const Cursor &second)
{
return !(first == second);
}
void PrintTo(CXCursorKind cursorKind, ::std::ostream *os) void PrintTo(CXCursorKind cursorKind, ::std::ostream *os)
{ {
ClangString cursorKindSpelling(clang_getCursorKindSpelling(cursorKind)); ClangString cursorKindSpelling(clang_getCursorKindSpelling(cursorKind));

View File

@@ -78,8 +78,11 @@ public:
Type nonPointerTupe() const; Type nonPointerTupe() const;
SourceLocation sourceLocation() const; SourceLocation sourceLocation() const;
CXSourceLocation cxSourceLocation() const;
SourceRange sourceRange() const; SourceRange sourceRange() const;
CXSourceRange cxSourceRange() const;
SourceRange commentRange() const; SourceRange commentRange() const;
bool hasSameSourceLocationAs(const Cursor &other) const;
Cursor definition() const; Cursor definition() const;
Cursor canonical() const; Cursor canonical() const;
@@ -90,7 +93,9 @@ public:
Cursor functionBaseDeclaration() const; Cursor functionBaseDeclaration() const;
Cursor functionBase() const; Cursor functionBase() const;
Cursor argument(int index) const; Cursor argument(int index) const;
std::vector<Cursor> outputArguments() const; void collectOutputArgumentRangesTo(
std::vector<CXSourceRange> &outputArgumentRanges) const;
std::vector<CXSourceRange> outputArgumentRanges() const;
CXCursorKind kind() const; CXCursorKind kind() const;
@@ -114,6 +119,7 @@ void Cursor::visit(VisitorCallback visitorCallback) const
} }
bool operator==(const Cursor &first, const Cursor &second); bool operator==(const Cursor &first, const Cursor &second);
bool operator!=(const Cursor &first, const Cursor &second);
void PrintTo(CXCursorKind cursorKind, ::std::ostream *os); void PrintTo(CXCursorKind cursorKind, ::std::ostream *os);
void PrintTo(const Cursor &cursor, ::std::ostream* os); void PrintTo(const Cursor &cursor, ::std::ostream* os);

View File

@@ -30,6 +30,7 @@
#include "highlightingmark.h" #include "highlightingmark.h"
#include "sourcelocation.h" #include "sourcelocation.h"
#include "sourcerange.h" #include "sourcerange.h"
#include "sourcerangecontainer.h"
#include <cstring> #include <cstring>
#include <ostream> #include <ostream>
@@ -40,15 +41,18 @@ namespace ClangBackEnd {
HighlightingMark::HighlightingMark(const CXCursor &cxCursor, HighlightingMark::HighlightingMark(const CXCursor &cxCursor,
CXToken *cxToken, CXToken *cxToken,
CXTranslationUnit cxTranslationUnit) CXTranslationUnit cxTranslationUnit,
std::vector<CXSourceRange> &currentOutputArgumentRanges)
: currentOutputArgumentRanges(&currentOutputArgumentRanges),
originalCursor(cxCursor)
{ {
const SourceRange sourceRange = clang_getTokenExtent(cxTranslationUnit, *cxToken); const SourceRange sourceRange = clang_getTokenExtent(cxTranslationUnit, *cxToken);
const auto start = sourceRange.start(); const auto start = sourceRange.start();
const auto end = sourceRange.end(); const auto end = sourceRange.end();
originalCursor = cxCursor;
line = start.line(); line = start.line();
column = start.column(); column = start.column();
offset = start.offset();
length = end.offset() - start.offset(); length = end.offset() - start.offset();
collectKinds(cxToken, originalCursor); collectKinds(cxToken, originalCursor);
} }
@@ -159,6 +163,17 @@ void HighlightingMark::variableKind(const Cursor &cursor)
types.mainHighlightingType = HighlightingType::LocalVariable; types.mainHighlightingType = HighlightingType::LocalVariable;
else else
types.mainHighlightingType = HighlightingType::GlobalVariable; types.mainHighlightingType = HighlightingType::GlobalVariable;
if (isOutputArgument())
types.mixinHighlightingTypes.push_back(HighlightingType::OutputArgument);
}
void HighlightingMark::fieldKind(const Cursor &)
{
types.mainHighlightingType = HighlightingType::Field;
if (isOutputArgument())
types.mixinHighlightingTypes.push_back(HighlightingType::OutputArgument);
} }
bool HighlightingMark::isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) const bool HighlightingMark::isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) const
@@ -185,6 +200,68 @@ void HighlightingMark::addExtraTypeIfFirstPass(HighlightingType type,
types.mixinHighlightingTypes.push_back(type); types.mixinHighlightingTypes.push_back(type);
} }
bool HighlightingMark::isArgumentInCurrentOutputArgumentLocations() const
{
auto originalSourceLocation = originalCursor.cxSourceLocation();
const auto isNotSameOutputArgument = [&] (const CXSourceRange &currentSourceRange) {
return !(originalSourceLocation.int_data >= currentSourceRange.begin_int_data
&& originalSourceLocation.int_data <= currentSourceRange.end_int_data);
};
auto partitionPoint = std::partition(currentOutputArgumentRanges->begin(),
currentOutputArgumentRanges->end(),
isNotSameOutputArgument);
bool isOutputArgument = partitionPoint != currentOutputArgumentRanges->end();
if (isOutputArgument)
currentOutputArgumentRanges->erase(partitionPoint, currentOutputArgumentRanges->end());
return isOutputArgument;
}
bool HighlightingMark::isOutputArgument() const
{
if (currentOutputArgumentRanges->empty())
return false;
return isArgumentInCurrentOutputArgumentLocations();
}
void HighlightingMark::collectOutputArguments(const Cursor &cursor)
{
cursor.collectOutputArgumentRangesTo(*currentOutputArgumentRanges);
filterOutPreviousOutputArguments();
}
namespace {
uint getStart(CXSourceRange cxSourceRange)
{
CXSourceLocation startSourceLocation = clang_getRangeStart(cxSourceRange);
uint startOffset;
clang_getFileLocation(startSourceLocation, nullptr, nullptr, nullptr, &startOffset);
return startOffset;
}
}
void HighlightingMark::filterOutPreviousOutputArguments()
{
auto isAfterLocation = [this] (CXSourceRange outputRange) {
return getStart(outputRange) > offset;
};
auto precedingBegin = std::partition(currentOutputArgumentRanges->begin(),
currentOutputArgumentRanges->end(),
isAfterLocation);
currentOutputArgumentRanges->erase(precedingBegin, currentOutputArgumentRanges->end());
}
void HighlightingMark::functionKind(const Cursor &cursor, Recursion recursion) void HighlightingMark::functionKind(const Cursor &cursor, Recursion recursion)
{ {
if (isRealDynamicCall(cursor) || isVirtualMethodDeclarationOrDefinition(cursor)) if (isRealDynamicCall(cursor) || isVirtualMethodDeclarationOrDefinition(cursor))
@@ -204,12 +281,13 @@ void HighlightingMark::identifierKind(const Cursor &cursor, Recursion recursion)
case CXCursor_CallExpr: case CXCursor_CallExpr:
case CXCursor_CXXMethod: functionKind(cursor, recursion); break; case CXCursor_CXXMethod: functionKind(cursor, recursion); break;
case CXCursor_NonTypeTemplateParameter: case CXCursor_NonTypeTemplateParameter:
case CXCursor_ParmDecl: types.mainHighlightingType = HighlightingType::LocalVariable; break; case CXCursor_CompoundStmt: types.mainHighlightingType = HighlightingType::LocalVariable; break;
case CXCursor_ParmDecl:
case CXCursor_VarDecl: variableKind(cursor); break; case CXCursor_VarDecl: variableKind(cursor); break;
case CXCursor_DeclRefExpr: identifierKind(cursor.referenced(), Recursion::RecursivePass); break; case CXCursor_DeclRefExpr: identifierKind(cursor.referenced(), Recursion::RecursivePass); break;
case CXCursor_MemberRefExpr: memberReferenceKind(cursor); break; case CXCursor_MemberRefExpr: memberReferenceKind(cursor); break;
case CXCursor_FieldDecl: case CXCursor_FieldDecl:
case CXCursor_MemberRef: case CXCursor_MemberRef: fieldKind(cursor); break;
case CXCursor_ObjCIvarDecl: case CXCursor_ObjCIvarDecl:
case CXCursor_ObjCPropertyDecl: case CXCursor_ObjCPropertyDecl:
case CXCursor_ObjCClassMethodDecl: case CXCursor_ObjCClassMethodDecl:
@@ -282,15 +360,17 @@ HighlightingType operatorKind(const Cursor &cursor)
return HighlightingType::Invalid; return HighlightingType::Invalid;
} }
HighlightingType punctationKind(const Cursor &cursor) }
HighlightingType HighlightingMark::punctuationKind(const Cursor &cursor)
{ {
switch (cursor.kind()) { switch (cursor.kind()) {
case CXCursor_DeclRefExpr: return operatorKind(cursor); case CXCursor_DeclRefExpr: return operatorKind(cursor);
case CXCursor_CallExpr: collectOutputArguments(cursor);
default: return HighlightingType::Invalid; default: return HighlightingType::Invalid;
} }
} }
}
void HighlightingMark::collectKinds(CXToken *cxToken, const Cursor &cursor) void HighlightingMark::collectKinds(CXToken *cxToken, const Cursor &cursor)
{ {
auto cxTokenKind = clang_getTokenKind(*cxToken); auto cxTokenKind = clang_getTokenKind(*cxToken);
@@ -299,7 +379,7 @@ void HighlightingMark::collectKinds(CXToken *cxToken, const Cursor &cursor)
switch (cxTokenKind) { switch (cxTokenKind) {
case CXToken_Keyword: types.mainHighlightingType = HighlightingType::Keyword; break; case CXToken_Keyword: types.mainHighlightingType = HighlightingType::Keyword; break;
case CXToken_Punctuation: types.mainHighlightingType = punctationKind(cursor); break; case CXToken_Punctuation: types.mainHighlightingType = punctuationKind(cursor); break;
case CXToken_Identifier: identifierKind(cursor, Recursion::FirstPass); break; case CXToken_Identifier: identifierKind(cursor, Recursion::FirstPass); break;
case CXToken_Comment: types.mainHighlightingType = HighlightingType::Comment; break; case CXToken_Comment: types.mainHighlightingType = HighlightingType::Comment; break;
case CXToken_Literal: types.mainHighlightingType = literalKind(cursor); break; case CXToken_Literal: types.mainHighlightingType = literalKind(cursor); break;

View File

@@ -45,7 +45,10 @@ class HighlightingMark
}; };
public: public:
HighlightingMark(const CXCursor &cxCursor, CXToken *cxToken, CXTranslationUnit cxTranslationUnit); HighlightingMark(const CXCursor &cxCursor,
CXToken *cxToken,
CXTranslationUnit cxTranslationUnit,
std::vector<CXSourceRange> &currentOutputArgumentRanges);
HighlightingMark(uint line, uint column, uint length, HighlightingTypes types); HighlightingMark(uint line, uint column, uint length, HighlightingTypes types);
HighlightingMark(uint line, uint column, uint length, HighlightingType type); HighlightingMark(uint line, uint column, uint length, HighlightingType type);
@@ -61,18 +64,26 @@ private:
void identifierKind(const Cursor &cursor, Recursion recursion); void identifierKind(const Cursor &cursor, Recursion recursion);
void referencedTypeKind(const Cursor &cursor); void referencedTypeKind(const Cursor &cursor);
void variableKind(const Cursor &cursor); void variableKind(const Cursor &cursor);
void fieldKind(const Cursor &cursor);
bool isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) const; bool isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) const;
void functionKind(const Cursor &cursor, Recursion recursion); void functionKind(const Cursor &cursor, Recursion recursion);
void memberReferenceKind(const Cursor &cursor); void memberReferenceKind(const Cursor &cursor);
HighlightingType punctuationKind(const Cursor &cursor);
void collectKinds(CXToken *cxToken, const Cursor &cursor); void collectKinds(CXToken *cxToken, const Cursor &cursor);
bool isRealDynamicCall(const Cursor &cursor) const; bool isRealDynamicCall(const Cursor &cursor) const;
void addExtraTypeIfFirstPass(HighlightingType type, Recursion recursion); void addExtraTypeIfFirstPass(HighlightingType type, Recursion recursion);
bool isOutputArgument() const;
void collectOutputArguments(const Cursor &cursor);
void filterOutPreviousOutputArguments();
bool isArgumentInCurrentOutputArgumentLocations() const;
private: private:
std::vector<CXSourceRange> *currentOutputArgumentRanges = nullptr;
Cursor originalCursor; Cursor originalCursor;
uint line; uint line;
uint column; uint column;
uint length; uint length;
uint offset = 0;
HighlightingTypes types; HighlightingTypes types;
}; };

View File

@@ -47,12 +47,18 @@ HighlightingMarks::~HighlightingMarks()
HighlightingMarks::const_iterator HighlightingMarks::begin() const HighlightingMarks::const_iterator HighlightingMarks::begin() const
{ {
return const_iterator(cxCursor.cbegin(), cxToken, cxTranslationUnit); return const_iterator(cxCursor.cbegin(),
cxToken,
cxTranslationUnit,
currentOutputArgumentRanges);
} }
HighlightingMarks::const_iterator HighlightingMarks::end() const HighlightingMarks::const_iterator HighlightingMarks::end() const
{ {
return const_iterator(cxCursor.cend(), cxToken + cxTokenCount, cxTranslationUnit); return const_iterator(cxCursor.cend(),
cxToken + cxTokenCount,
cxTranslationUnit,
currentOutputArgumentRanges);
} }
QVector<HighlightingMarkContainer> HighlightingMarks::toHighlightingMarksContainers() const QVector<HighlightingMarkContainer> HighlightingMarks::toHighlightingMarksContainers() const
@@ -67,11 +73,19 @@ QVector<HighlightingMarkContainer> HighlightingMarks::toHighlightingMarksContain
&& !highlightMark.hasMainType(HighlightingType::Comment); && !highlightMark.hasMainType(HighlightingType::Comment);
}; };
std::copy_if(begin(), end(), std::back_inserter(containers), isValidHighlightMark); for (const HighlightingMark &highlightMark : *this) {
if (isValidHighlightMark(highlightMark))
containers.push_back(highlightMark);
}
return containers; return containers;
} }
bool HighlightingMarks::currentOutputArgumentRangesAreEmpty() const
{
return currentOutputArgumentRanges.empty();
}
bool HighlightingMarks::isEmpty() const bool HighlightingMarks::isEmpty() const
{ {
return cxTokenCount == 0; return cxTokenCount == 0;
@@ -89,7 +103,10 @@ uint HighlightingMarks::size() const
HighlightingMark HighlightingMarks::operator[](size_t index) const HighlightingMark HighlightingMarks::operator[](size_t index) const
{ {
return HighlightingMark(cxCursor[index], cxToken + index, cxTranslationUnit); return HighlightingMark(cxCursor[index],
cxToken + index,
cxTranslationUnit,
currentOutputArgumentRanges);
} }
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -58,7 +58,10 @@ public:
QVector<HighlightingMarkContainer> toHighlightingMarksContainers() const; QVector<HighlightingMarkContainer> toHighlightingMarksContainers() const;
bool currentOutputArgumentRangesAreEmpty() const;
private: private:
mutable std::vector<CXSourceRange> currentOutputArgumentRanges;
CXTranslationUnit cxTranslationUnit = nullptr; CXTranslationUnit cxTranslationUnit = nullptr;
CXToken *const cxToken = nullptr; CXToken *const cxToken = nullptr;
const uint cxTokenCount = 0; const uint cxTokenCount = 0;

View File

@@ -44,10 +44,12 @@ class HighlightingMarksIterator : public std::iterator<std::forward_iterator_tag
public: public:
HighlightingMarksIterator(std::vector<CXCursor>::const_iterator cxCursorIterator, HighlightingMarksIterator(std::vector<CXCursor>::const_iterator cxCursorIterator,
CXToken *cxToken, CXToken *cxToken,
CXTranslationUnit cxTranslationUnit) CXTranslationUnit cxTranslationUnit,
std::vector<CXSourceRange> &currentOutputArgumentRanges)
: cxCursorIterator(cxCursorIterator), : cxCursorIterator(cxCursorIterator),
cxToken(cxToken), cxToken(cxToken),
cxTranslationUnit(cxTranslationUnit) cxTranslationUnit(cxTranslationUnit),
currentOutputArgumentRanges(currentOutputArgumentRanges)
{} {}
HighlightingMarksIterator& operator++() HighlightingMarksIterator& operator++()
@@ -60,7 +62,10 @@ public:
HighlightingMarksIterator operator++(int) HighlightingMarksIterator operator++(int)
{ {
return HighlightingMarksIterator(cxCursorIterator++, cxToken++, cxTranslationUnit); return HighlightingMarksIterator(cxCursorIterator++,
cxToken++,
cxTranslationUnit,
currentOutputArgumentRanges);
} }
bool operator==(HighlightingMarksIterator other) const bool operator==(HighlightingMarksIterator other) const
@@ -75,13 +80,17 @@ public:
HighlightingMark operator*() HighlightingMark operator*()
{ {
return HighlightingMark(*cxCursorIterator, cxToken, cxTranslationUnit); return HighlightingMark(*cxCursorIterator,
cxToken,
cxTranslationUnit,
currentOutputArgumentRanges);
} }
private: private:
std::vector<CXCursor>::const_iterator cxCursorIterator; std::vector<CXCursor>::const_iterator cxCursorIterator;
CXToken *cxToken; CXToken *cxToken;
CXTranslationUnit cxTranslationUnit; CXTranslationUnit cxTranslationUnit;
std::vector<CXSourceRange> &currentOutputArgumentRanges;
}; };
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -0,0 +1,40 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <clang-c/Index.h>
inline
bool operator==(const CXSourceLocation &first, const CXSourceLocation &second)
{
return clang_equalLocations(first, second);
}
inline
bool operator==(const CXSourceRange &first, const CXSourceRange &second)
{
return clang_equalRanges(first, second);
}

View File

@@ -25,6 +25,8 @@
#include "googletest.h" #include "googletest.h"
#include "clangcompareoperators.h"
#include <clangdocument.h> #include <clangdocument.h>
#include <clangdocuments.h> #include <clangdocuments.h>
#include <clangstring.h> #include <clangstring.h>
@@ -85,6 +87,8 @@ protected:
const TranslationUnit &translationUnit = d->translationUnit; const TranslationUnit &translationUnit = d->translationUnit;
}; };
TEST_F(Cursor, CreateNullCursor) TEST_F(Cursor, CreateNullCursor)
{ {
::Cursor cursor; ::Cursor cursor;
@@ -489,21 +493,21 @@ TEST_F(Cursor, HasNotFinaAttributeInClass)
TEST_F(Cursor, HasOutputValues) TEST_F(Cursor, HasOutputValues)
{ {
auto callExpressionCursor = translationUnit.cursorAt(117, 19); auto callExpressionCursor = translationUnit.cursorAt(117, 19);
auto outputArgumentExpectedCursor = translationUnit.cursorAt(117, 20); auto outputArgumentExpectedSourceLocation = translationUnit.cursorAt(117, 20).cxSourceRange();
auto outputArguments = callExpressionCursor.outputArguments(); auto outputArgumentLocations = callExpressionCursor.outputArgumentRanges();
ASSERT_THAT(outputArguments.size(), 1); ASSERT_THAT(outputArgumentLocations.size(), 2);
ASSERT_THAT(outputArguments[0], outputArgumentExpectedCursor); ASSERT_THAT(outputArgumentLocations[0], outputArgumentExpectedSourceLocation);
} }
TEST_F(Cursor, HasOnlyInputValues) TEST_F(Cursor, HasOnlyInputValues)
{ {
auto callExpressionCursor = translationUnit.cursorAt(118, 18); auto callExpressionCursor = translationUnit.cursorAt(118, 18);
auto outputArguments = callExpressionCursor.outputArguments(); auto outputArgumentLocations = callExpressionCursor.outputArgumentRanges();
ASSERT_THAT(outputArguments, IsEmpty()); ASSERT_THAT(outputArgumentLocations, IsEmpty());
} }
TEST_F(Cursor, ArgumentCountIsZero) TEST_F(Cursor, ArgumentCountIsZero)
@@ -748,58 +752,58 @@ TEST_F(Cursor, PointerIsNotRefencingConstant)
ASSERT_FALSE(argument.isReferencingConstant()); ASSERT_FALSE(argument.isReferencingConstant());
} }
TEST_F(Cursor, PointerIsOutputParameter) TEST_F(Cursor, PointerIsOutputArgument)
{ {
auto callExpressionCursor = translationUnit.cursorAt(127, 13); auto callExpressionCursor = translationUnit.cursorAt(127, 13);
auto argument = callExpressionCursor.type().argument(0); auto argument = callExpressionCursor.type().argument(0);
ASSERT_TRUE(argument.isOutputParameter()); ASSERT_TRUE(argument.isOutputArgument());
} }
TEST_F(Cursor, ConstantReferenceIsNotOutputParameter) TEST_F(Cursor, ConstantReferenceIsNotOutputArgument)
{ {
auto callExpressionCursor = translationUnit.cursorAt(125, 26); auto callExpressionCursor = translationUnit.cursorAt(125, 26);
auto argument = callExpressionCursor.type().argument(0); auto argument = callExpressionCursor.type().argument(0);
ASSERT_FALSE(argument.isOutputParameter()); ASSERT_FALSE(argument.isOutputArgument());
} }
TEST_F(Cursor, PointerToConstantIsNotOutputParameter) TEST_F(Cursor, PointerToConstantIsNotOutputArgument)
{ {
auto callExpressionCursor = translationUnit.cursorAt(126, 20); auto callExpressionCursor = translationUnit.cursorAt(126, 20);
auto argument = callExpressionCursor.type().argument(0); auto argument = callExpressionCursor.type().argument(0);
ASSERT_FALSE(argument.isOutputParameter()) << argument.isConstant() << argument.pointeeType().isConstant(); ASSERT_FALSE(argument.isOutputArgument()) << argument.isConstant() << argument.pointeeType().isConstant();
} }
TEST_F(Cursor, ConstantPointerIsNotOutputParameter) TEST_F(Cursor, ConstantPointerIsNotOutputArgument)
{ {
auto callExpressionCursor = translationUnit.cursorAt(128, 21); auto callExpressionCursor = translationUnit.cursorAt(128, 21);
auto argument = callExpressionCursor.type().argument(0); auto argument = callExpressionCursor.type().argument(0);
ASSERT_TRUE(argument.isOutputParameter()); ASSERT_TRUE(argument.isOutputArgument());
} }
TEST_F(Cursor, ReferenceIsOutputParameter) TEST_F(Cursor, ReferenceIsOutputArgument)
{ {
auto callExpressionCursor = translationUnit.cursorAt(124, 21); auto callExpressionCursor = translationUnit.cursorAt(124, 21);
auto argument = callExpressionCursor.type().argument(0); auto argument = callExpressionCursor.type().argument(0);
ASSERT_TRUE(argument.isOutputParameter()); ASSERT_TRUE(argument.isOutputArgument());
} }
TEST_F(Cursor, ConstReferenceIsNotOutputParameter) TEST_F(Cursor, ConstReferenceIsNotOutputArgument)
{ {
auto callExpressionCursor = translationUnit.cursorAt(125, 26); auto callExpressionCursor = translationUnit.cursorAt(125, 26);
auto argument = callExpressionCursor.type().argument(0); auto argument = callExpressionCursor.type().argument(0);
ASSERT_FALSE(argument.isOutputParameter()); ASSERT_FALSE(argument.isOutputArgument());
} }
Data *Cursor::d; Data *Cursor::d;

View File

@@ -278,12 +278,12 @@ void FinalClass::FinalClassThisCall()
} }
void OutputParameter(int &one, const int &two, int *three=0); void OutputArgument(int &one, const int &two, int *three=0);
void f12() void f12b()
{ {
int One; int One;
OutputParameter(One, 2); OutputArgument(One, 2);
} }
#include <highlightingmarks.h> #include <highlightingmarks.h>
@@ -445,3 +445,83 @@ struct LambdaTester
lambda(var2); lambda(var2);
} }
}; };
void NonConstReferenceArgument(int &argument);
void f22()
{
int x = 1;
NonConstReferenceArgument(x);
}
void ConstReferenceArgument(const int &argument);
void f23()
{
int x = 1;
ConstReferenceArgument(x);
}
void RValueReferenceArgument(int &&argument);
void f24()
{
int x = 1;
RValueReferenceArgument(static_cast<int&&>(x));
}
void NonConstPointerArgument(int *argument);
void f25()
{
int *x;
NonConstPointerArgument(x);
}
void ConstPointerArgument(const int *argument);
void f26()
{
int *x;
ConstPointerArgument(x);
}
void NonConstReferenceArgumentCallInsideCall(int x, int &argument);
int GetArgument(int x);
void f27()
{
int x = 1;
NonConstReferenceArgumentCallInsideCall(GetArgument(x), x);
}
void f28(int &Reference)
{
NonConstReferenceArgument(Reference);
}
void f29()
{
int x;
NonConstPointerArgument(&x);
}
struct NonConstPointerArgumentAsMemberOfClass
{
int member;
};
void f30()
{
NonConstPointerArgumentAsMemberOfClass instance;
NonConstReferenceArgument(instance.member);
}

View File

@@ -959,6 +959,106 @@ TEST_F(HighlightingMarks, TypeDefDeclarationUsage)
ASSERT_THAT(infos[0], HasOnlyType(HighlightingType::Type)); ASSERT_THAT(infos[0], HasOnlyType(HighlightingType::Type));
} }
TEST_F(HighlightingMarks, NonConstReferenceArgument)
{
const auto infos = translationUnit.highlightingMarksInRange(sourceRange(455, 35));
infos[1];
ASSERT_THAT(infos[2],
HasTwoTypes(HighlightingType::LocalVariable, HighlightingType::OutputArgument));
}
TEST_F(HighlightingMarks, ConstReferenceArgument)
{
const auto infos = translationUnit.highlightingMarksInRange(sourceRange(464, 32));
infos[1];
ASSERT_THAT(infos[2],
HasOnlyType(HighlightingType::LocalVariable));
}
TEST_F(HighlightingMarks, RValueReferenceArgument)
{
const auto infos = translationUnit.highlightingMarksInRange(sourceRange(473, 52));
infos[1];
ASSERT_THAT(infos[8],
HasOnlyType(HighlightingType::LocalVariable));
}
TEST_F(HighlightingMarks, NonConstPointerArgument)
{
const auto infos = translationUnit.highlightingMarksInRange(sourceRange(482, 33));
infos[1];
ASSERT_THAT(infos[2],
HasTwoTypes(HighlightingType::LocalVariable, HighlightingType::OutputArgument));
}
TEST_F(HighlightingMarks, ConstPointerArgument)
{
const auto infos = translationUnit.highlightingMarksInRange(sourceRange(491, 30));
infos[1];
ASSERT_THAT(infos[2],
HasOnlyType(HighlightingType::LocalVariable));
}
TEST_F(HighlightingMarks, NonConstReferenceArgumentCallInsideCall)
{
const auto infos = translationUnit.highlightingMarksInRange(sourceRange(501, 64));
infos[1];
infos[3];
ASSERT_THAT(infos[7],
HasTwoTypes(HighlightingType::LocalVariable, HighlightingType::OutputArgument));
}
TEST_F(HighlightingMarks, OutputArgumentsAreEmptyAfterIteration)
{
const auto infos = translationUnit.highlightingMarksInRange(sourceRange(501, 63));
for (const auto &info : infos ) {}
ASSERT_TRUE(infos.currentOutputArgumentRangesAreEmpty());
}
TEST_F(HighlightingMarks, NonConstReferenceArgumentFromFunctionParameter)
{
const auto infos = translationUnit.highlightingMarksInRange(sourceRange(506, 42));
infos[1];
ASSERT_THAT(infos[2],
HasTwoTypes(HighlightingType::LocalVariable, HighlightingType::OutputArgument));
}
TEST_F(HighlightingMarks, NonConstPointerArgumentAsExpression)
{
const auto infos = translationUnit.highlightingMarksInRange(sourceRange(513, 33));
infos[1];
ASSERT_THAT(infos[3],
HasTwoTypes(HighlightingType::LocalVariable, HighlightingType::OutputArgument));
}
TEST_F(HighlightingMarks, NonConstPointerArgumentAsMemberOfClass)
{
const auto infos = translationUnit.highlightingMarksInRange(sourceRange(525, 46));
infos[1];
ASSERT_THAT(infos[4],
HasTwoTypes(HighlightingType::Field, HighlightingType::OutputArgument));
}
TEST_F(HighlightingMarks, DISABLED_EnumerationTypeDef) TEST_F(HighlightingMarks, DISABLED_EnumerationTypeDef)
{ {
const auto infos = translationUnit.highlightingMarksInRange(sourceRange(424, 41)); const auto infos = translationUnit.highlightingMarksInRange(sourceRange(424, 41));

View File

@@ -118,6 +118,7 @@ HEADERS += \
chunksreportedmonitor.h \ chunksreportedmonitor.h \
clangasyncjob-base.h \ clangasyncjob-base.h \
diagnosticcontainer-matcher.h \ diagnosticcontainer-matcher.h \
clangcompareoperators.h \
dummyclangipcclient.h \ dummyclangipcclient.h \
mockclangcodemodelclient.h \ mockclangcodemodelclient.h \
mockclangcodemodelserver.h mockclangcodemodelserver.h