TextEditor: Implement highlighting of function definitions

This allows users to style function names at their definitions.

Once set, the XML-style token "FunctionDefinition" will
highlight all function definitions: the style option is a
mixin to Function and Virtual Function.

TEST=Default themes and locally hacked themes that lack Function,
FunctionDefinition, Declaration-styling look as they did before
this patch.

Requires Clang.

Task-number: QTCREATORBUG-16625
Change-Id: I49d8e401211bdf28ff74699feac16fe98f6d64ce
Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
Hugo Holgersson
2016-07-17 00:29:33 +02:00
parent e050622f55
commit bf3c67e0d0
12 changed files with 85 additions and 14 deletions

View File

@@ -84,8 +84,9 @@ enum class HighlightingType : quint8
PreprocessorDefinition,
PreprocessorExpansion,
Label,
OutputArgument,
Declaration
Declaration,
FunctionDefinition,
OutputArgument
};
enum class CompletionCorrection : quint32

View File

@@ -50,6 +50,7 @@ static const char *highlightingTypeToCStringLiteral(HighlightingType type)
RETURN_TEXT_FOR_CASE(Operator);
RETURN_TEXT_FOR_CASE(Preprocessor);
RETURN_TEXT_FOR_CASE(Label);
RETURN_TEXT_FOR_CASE(FunctionDefinition);
RETURN_TEXT_FOR_CASE(OutputArgument);
RETURN_TEXT_FOR_CASE(PreprocessorDefinition);
RETURN_TEXT_FOR_CASE(PreprocessorExpansion);

View File

@@ -63,6 +63,8 @@ TextEditor::TextStyle toTextStyle(ClangBackEnd::HighlightingType type)
return TextEditor::C_PREPROCESSOR;
case HighlightingType::Declaration:
return TextEditor::C_DECLARATION;
case HighlightingType::FunctionDefinition:
return TextEditor::C_FUNCTION_DEFINITION;
case HighlightingType::OutputArgument:
return TextEditor::C_OUTPUT_ARGUMENT;
case HighlightingType::Operator:

View File

@@ -46,6 +46,10 @@ public:
Format() = default;
Format(const QColor &foreground, const QColor &background);
static Format createMixinFormat() {
return Format(QColor(), QColor());
}
QColor foreground() const { return m_foreground; }
void setForeground(const QColor &foreground);

View File

@@ -101,8 +101,9 @@ const char *nameForStyle(TextStyle style)
case C_WARNING: return "Warning";
case C_WARNING_CONTEXT: return "WarningContext";
case C_DECLARATION: return "Declaration";
case C_OUTPUT_ARGUMENT: return "OutputArgument";
case C_DECLARATION: return "Declaration";
case C_FUNCTION_DEFINITION: return "FunctionDefinition";
case C_OUTPUT_ARGUMENT: return "OutputArgument";
case C_LAST_STYLE_SENTINEL: return "LastStyleSentinel";
}

View File

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

View File

@@ -288,6 +288,8 @@ TextEditorSettings::TextEditorSettings(QObject *parent)
tr("Applied to lines describing changes in VCS log."),
Format(QColor(192, 0, 0), QColor()));
// Mixin categories
formatDescr.emplace_back(C_ERROR,
tr("Error"),
tr("Underline color of error diagnostics."),
@@ -312,14 +314,19 @@ TextEditorSettings::TextEditorSettings(QObject *parent)
QColor(255, 190, 0),
QTextCharFormat::DotLine,
FormatDescription::ShowUnderlineControl);
Format declarationFormat;
Format declarationFormat = Format::createMixinFormat();
declarationFormat.setBold(true);
formatDescr.emplace_back(C_DECLARATION,
tr("Function Declaration"),
tr("Style adjustments to function declarations."),
tr("Style adjustments to (function) declarations."),
declarationFormat,
FormatDescription::ShowFontUnderlineAndRelativeControls);
Format outputArgumentFormat;
formatDescr.emplace_back(C_FUNCTION_DEFINITION,
tr("Function Definition"),
tr("Name of function at its definition."),
Format::createMixinFormat(),
FormatDescription::ShowFontUnderlineAndRelativeControls);
Format outputArgumentFormat = Format::createMixinFormat();
outputArgumentFormat.setItalic(true);
formatDescr.emplace_back(C_OUTPUT_ARGUMENT,
tr("Output Argument"),

View File

@@ -84,6 +84,10 @@ bool HighlightingMark::hasMainType(HighlightingType type) const
return m_types.mainHighlightingType == type;
}
unsigned HighlightingMark::mixinSize() const {
return m_types.mixinHighlightingTypes.size();
}
bool HighlightingMark::hasMixinType(HighlightingType type) const
{
auto found = std::find(m_types.mixinHighlightingTypes.begin(),
@@ -93,6 +97,12 @@ bool HighlightingMark::hasMixinType(HighlightingType type) const
return found != m_types.mixinHighlightingTypes.end();
}
bool HighlightingMark::hasMixinTypeAt(uint position, HighlightingType type) const
{
return m_types.mixinHighlightingTypes.size() > position &&
m_types.mixinHighlightingTypes.at(position) == type;
}
bool HighlightingMark::hasOnlyType(HighlightingType type) const
{
return m_types.mixinHighlightingTypes.size() == 0 && hasMainType(type);
@@ -191,17 +201,22 @@ void HighlightingMark::fieldKind(const Cursor &)
m_types.mixinHighlightingTypes.push_back(HighlightingType::OutputArgument);
}
bool HighlightingMark::isDefinition() const
{
return m_originalCursor.isDefinition();
}
bool HighlightingMark::isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) const
{
return cursor.isVirtualMethod()
&& (m_originalCursor.isDeclaration() || m_originalCursor.isDefinition());
}
namespace {
bool isNotFinalFunction(const Cursor &cursor)
{
return !cursor.hasFinalFunctionAttribute();
}
}
bool HighlightingMark::isRealDynamicCall(const Cursor &cursor) const
{
@@ -285,6 +300,9 @@ void HighlightingMark::functionKind(const Cursor &cursor, Recursion recursion)
m_types.mixinHighlightingTypes.push_back(HighlightingType::OutputArgument);
addExtraTypeIfFirstPass(HighlightingType::Declaration, recursion);
if (isDefinition())
addExtraTypeIfFirstPass(HighlightingType::FunctionDefinition, recursion);
}
void HighlightingMark::identifierKind(const Cursor &cursor, Recursion recursion)

View File

@@ -53,7 +53,9 @@ public:
bool hasInvalidMainType() const;
bool hasMainType(HighlightingType type) const;
unsigned mixinSize() const;
bool hasMixinType(HighlightingType type) const;
bool hasMixinTypeAt(uint, HighlightingType type) const;
bool hasOnlyType(HighlightingType type) const;
bool hasFunctionArguments() const;
@@ -66,6 +68,7 @@ private:
void variableKind(const Cursor &cursor);
void fieldKind(const Cursor &cursor);
bool isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) const;
bool isDefinition() const;
void functionKind(const Cursor &cursor, Recursion recursion);
void memberReferenceKind(const Cursor &cursor);
HighlightingType punctuationKind(const Cursor &cursor);

View File

@@ -629,6 +629,7 @@ void ClangCodeModelServer::expectDocumentAnnotationsChangedForFileBWithSpecificH
HighlightingTypes types;
types.mainHighlightingType = ClangBackEnd::HighlightingType::Function;
types.mixinHighlightingTypes.push_back(ClangBackEnd::HighlightingType::Declaration);
types.mixinHighlightingTypes.push_back(ClangBackEnd::HighlightingType::FunctionDefinition);
const HighlightingMarkContainer highlightingMark(1, 6, 8, types, true);
EXPECT_CALL(mockClangCodeModelClient,

View File

@@ -582,3 +582,9 @@ void f32()
namespace N { template <typename T> void SizeIs(); }
using N::SizeIs;
void BaseClass::VirtualFunction() {}
class WithVirtualFunctionDefined {
virtual void VirtualFunctionDefinition() {};
};

View File

@@ -95,15 +95,27 @@ MATCHER_P2(HasTwoTypes, firstType, secondType,
+ PrintToString(secondType)
)
{
return arg.hasMainType(firstType) && arg.hasMixinType(secondType);
return arg.hasMainType(firstType) && arg.hasMixinTypeAt(0, secondType) && arg.mixinSize() == 1;
}
MATCHER_P(HasMixin, firstType,
MATCHER_P3(HasThreeTypes, firstType, secondType, thirdType,
std::string(negation ? "isn't " : "is ")
+ PrintToString(firstType)
+ ", "
+ PrintToString(secondType)
+ " and "
+ PrintToString(thirdType)
)
{
return arg.hasMainType(firstType) && arg.hasMixinTypeAt(0, secondType) && arg.hasMixinTypeAt(1, thirdType) && arg.mixinSize() == 2;
}
MATCHER_P(HasMixin, mixinType,
std::string(negation ? "isn't " : "is ")
+ PrintToString(firstType)
+ PrintToString(mixinType)
)
{
return arg.hasMixinType(firstType);
return arg.hasMixinType(mixinType);
}
struct Data {
@@ -244,14 +256,28 @@ TEST_F(HighlightingMarks, FunctionDefinition)
{
const auto infos = translationUnit.highlightingMarksInRange(sourceRange(45, 20));
ASSERT_THAT(infos[1], HasTwoTypes(HighlightingType::Function, HighlightingType::Declaration));
ASSERT_THAT(infos[1], HasThreeTypes(HighlightingType::Function, HighlightingType::Declaration, HighlightingType::FunctionDefinition));
}
TEST_F(HighlightingMarks, MemberFunctionDefinition)
{
const auto infos = translationUnit.highlightingMarksInRange(sourceRange(52, 29));
ASSERT_THAT(infos[1], HasTwoTypes(HighlightingType::Function, HighlightingType::Declaration));
ASSERT_THAT(infos[1], HasThreeTypes(HighlightingType::Function, HighlightingType::Declaration, HighlightingType::FunctionDefinition));
}
TEST_F(HighlightingMarks, VirtualMemberFunctionDefinitionOutsideOfClassBody)
{
const auto infos = translationUnit.highlightingMarksInRange(sourceRange(586, 37));
ASSERT_THAT(infos[3], HasThreeTypes(HighlightingType::VirtualFunction, HighlightingType::Declaration, HighlightingType::FunctionDefinition));
}
TEST_F(HighlightingMarks, VirtualMemberFunctionDefinitionInsideOfClassBody)
{
const auto infos = translationUnit.highlightingMarksInRange(sourceRange(589, 47));
ASSERT_THAT(infos[2], HasThreeTypes(HighlightingType::VirtualFunction, HighlightingType::Declaration, HighlightingType::FunctionDefinition));
}
TEST_F(HighlightingMarks, FunctionDeclaration)