mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-25 11:22:55 +00:00
348 lines
11 KiB
C++
348 lines
11 KiB
C++
/*
|
|
* KDevelop C++ Code Completion Support
|
|
*
|
|
* Copyright 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Library General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public
|
|
* License along with this program; if not, write to the
|
|
* Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "helpers.h"
|
|
#include "item.h"
|
|
#include <QList>
|
|
#include <QVariant>
|
|
#include <language/duchain/declaration.h>
|
|
#include <language/duchain/abstractfunctiondeclaration.h>
|
|
#include <language/duchain/duchainutils.h>
|
|
#include <QTextFormat>
|
|
#include "../cppduchain/cpptypes.h"
|
|
#include "../cppduchain/cppduchain.h"
|
|
#include "../cppduchain/overloadresolutionhelper.h"
|
|
#include "../cppduchain/viablefunctions.h"
|
|
#include <templatedeclaration.h>
|
|
#include <templateparameterdeclaration.h>
|
|
#include "../cpputils.h"
|
|
#include "context.h"
|
|
|
|
const int desiredArgumentTypeLength = 20;
|
|
const int maxDefaultParameterLength = 30;
|
|
|
|
using namespace KDevelop;
|
|
|
|
namespace Cpp {
|
|
|
|
void createArgumentList(const NormalDeclarationCompletionItem& item, QString& ret, QList<QVariant>* highlighting, bool includeDefaultParams, bool noShortening )
|
|
{
|
|
Declaration* dec(item.declaration().data());
|
|
|
|
Cpp::CodeCompletionContext::Function f;
|
|
DUContext* ctx = 0;
|
|
if(item.completionContext() && item.completionContext()->duContext()) {
|
|
ctx = item.completionContext()->duContext();
|
|
}
|
|
|
|
if( item.completionContext() && item.completionContext()->accessType() == Cpp::CodeCompletionContext::FunctionCallAccess && item.completionContext()->functions().count() > item.listOffset )
|
|
f = item.completionContext()->functions()[item.listOffset];
|
|
|
|
QTextFormat normalFormat(QTextFormat::CharFormat);
|
|
QTextFormat highlightFormat; //highlightFormat is invalid, so kate uses the match-quality dependent color.
|
|
QTextCharFormat boldFormat;
|
|
boldFormat.setFontWeight(QFont::Bold);
|
|
|
|
AbstractFunctionDeclaration* decl = dynamic_cast<AbstractFunctionDeclaration*>(dec);
|
|
FunctionType::Ptr functionType = dec->type<FunctionType>();
|
|
if (functionType && decl) {
|
|
|
|
QVector<Declaration*> parameters;
|
|
if( DUChainUtils::getArgumentContext(dec) )
|
|
parameters = DUChainUtils::getArgumentContext(dec)->localDeclarations(ctx ? ctx->topContext() : 0);
|
|
|
|
// QStringList defaultParams = decl->defaultParameters();
|
|
|
|
QVector<Declaration*>::const_iterator paramNameIt = parameters.constBegin();
|
|
uint defaultParamNum = 0;
|
|
|
|
int firstDefaultParam = functionType->arguments().count() - decl->defaultParametersSize();
|
|
|
|
int textFormatStart = ret.length();
|
|
ret += "(";
|
|
|
|
if( highlighting && ret.length() != textFormatStart )
|
|
{
|
|
//Add a default-highlighting for the passed text
|
|
*highlighting << QVariant(textFormatStart);
|
|
*highlighting << QVariant(ret.length() - textFormatStart);
|
|
*highlighting << boldFormat;
|
|
textFormatStart = ret.length();
|
|
}
|
|
|
|
bool first = true;
|
|
int num = 0;
|
|
|
|
const KDevVarLengthArray<Cpp::ViableFunction::ParameterConversion>& conversions = f.function.parameterConversions();
|
|
int parameterConversion = 0;
|
|
|
|
foreach (const AbstractType::Ptr& argument, functionType->arguments()) {
|
|
if (first)
|
|
first = false;
|
|
else
|
|
ret += ", ";
|
|
|
|
bool doHighlight = false;
|
|
QTextFormat doFormat = normalFormat;
|
|
|
|
if( ( f.function.isValid() && num == f.matchedArguments ) )
|
|
{
|
|
doHighlight = true;
|
|
doFormat = highlightFormat;
|
|
|
|
} else if( num < f.matchedArguments )
|
|
{
|
|
doHighlight = true;
|
|
QTextCharFormat format;
|
|
|
|
if( parameterConversion != conversions.size() ) {
|
|
//Interpolate the color
|
|
quint64 badMatchColor = 0xff7777ff; //Full blue
|
|
quint64 goodMatchColor = 0xff77ff77; //Full green
|
|
|
|
uint totalColor = (badMatchColor*(Cpp::MaximumConversionResult-conversions[parameterConversion].rank) + goodMatchColor*(conversions[parameterConversion]).rank)/Cpp::MaximumConversionResult;
|
|
|
|
format.setUnderlineStyle( QTextCharFormat::WaveUnderline );
|
|
format.setUnderlineColor( QColor(totalColor) );
|
|
|
|
++parameterConversion;
|
|
doFormat = format;
|
|
}
|
|
}
|
|
|
|
if( doHighlight )
|
|
{
|
|
if( highlighting && ret.length() != textFormatStart )
|
|
{
|
|
//Add a default-highlighting for the passed text
|
|
*highlighting << QVariant(textFormatStart);
|
|
*highlighting << QVariant(ret.length() - textFormatStart);
|
|
*highlighting << QVariant(normalFormat);
|
|
textFormatStart = ret.length();
|
|
}
|
|
}
|
|
|
|
if( paramNameIt != parameters.constEnd() /*&& !(*paramNameIt)->identifier().isEmpty()*/ ) {
|
|
// make sure that something like 'int foo[][1][2]' gets printed as such
|
|
// and not like 'int[0][1][2] foo'
|
|
AbstractType::Ptr type;
|
|
if(ctx)
|
|
type = typeForShortenedString(*paramNameIt);
|
|
else
|
|
type = argument;
|
|
|
|
QString arrayAppendix;
|
|
ArrayType::Ptr arrayType;
|
|
while ((arrayType = type.cast<ArrayType>())) {
|
|
type = arrayType->elementType();
|
|
//note: we have to prepend since we iterate from outside, i.e. from right to left.
|
|
if (arrayType->dimension()) {
|
|
arrayAppendix.prepend(QString("[%1]").arg(arrayType->dimension()));
|
|
} else {
|
|
// dimensionless
|
|
arrayAppendix.prepend("[]");
|
|
}
|
|
}
|
|
|
|
if(noShortening) {
|
|
ret += Cpp::shortenedTypeString(type, ctx, 1000000);
|
|
}else
|
|
ret += Cpp::shortenedTypeString(type, ctx, desiredArgumentTypeLength, item.stripPrefix());
|
|
const QString ident = (*paramNameIt)->identifier().toString();
|
|
if (!ident.isEmpty()) {
|
|
ret += " " + ident;
|
|
}
|
|
ret += arrayAppendix;
|
|
} else if (argument)
|
|
ret += argument->toString();
|
|
else
|
|
ret += "<incomplete type>";
|
|
|
|
if( doHighlight )
|
|
{
|
|
if( highlighting && ret.length() != textFormatStart )
|
|
{
|
|
*highlighting << QVariant(textFormatStart);
|
|
*highlighting << QVariant(ret.length() - textFormatStart);
|
|
*highlighting << doFormat;
|
|
textFormatStart = ret.length();
|
|
}
|
|
}
|
|
|
|
if( num >= firstDefaultParam && includeDefaultParams ) {
|
|
ret += " = ";
|
|
|
|
QString defaultParam = decl->defaultParameters()[defaultParamNum].str();
|
|
if(defaultParam.length() <= maxDefaultParameterLength)
|
|
ret += defaultParam;
|
|
else
|
|
ret += "...";
|
|
|
|
++defaultParamNum;
|
|
}
|
|
|
|
++num;
|
|
if( paramNameIt != parameters.constEnd() )
|
|
++paramNameIt;
|
|
}
|
|
|
|
if( highlighting && ret.length() != textFormatStart )
|
|
{
|
|
*highlighting << QVariant(textFormatStart);
|
|
*highlighting << QVariant(ret.length() - textFormatStart);
|
|
*highlighting << normalFormat;
|
|
textFormatStart = ret.length();
|
|
}
|
|
|
|
ret += ')';
|
|
|
|
if( highlighting && ret.length() != textFormatStart )
|
|
{
|
|
*highlighting << QVariant(textFormatStart);
|
|
*highlighting << QVariant(ret.length() - textFormatStart);
|
|
*highlighting << boldFormat;
|
|
textFormatStart = ret.length();
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
void createTemplateArgumentList(const NormalDeclarationCompletionItem& item, QString& ret, QList<QVariant>* highlighting, bool includeDefaultParams )
|
|
{
|
|
Q_UNUSED(includeDefaultParams);
|
|
|
|
Declaration* dec(item.declaration().data());
|
|
|
|
QTextFormat normalFormat(QTextFormat::CharFormat);
|
|
QTextFormat highlightFormat; //highlightFormat is invalid, so kate uses the match-quality dependent color.
|
|
QTextCharFormat boldFormat;
|
|
boldFormat.setFontWeight(QFont::Bold);
|
|
|
|
TemplateDeclaration* tempDecl(dynamic_cast<TemplateDeclaration*>(dec));
|
|
if(!tempDecl)
|
|
return;
|
|
|
|
DUContext* templateContext = tempDecl->templateContext( dec->topContext() );
|
|
|
|
if(!templateContext)
|
|
return;
|
|
|
|
QVector<Declaration*> parameters = templateContext->localDeclarations();
|
|
|
|
int textFormatStart = ret.length();
|
|
ret += "<";
|
|
|
|
if( highlighting && ret.length() != textFormatStart )
|
|
{
|
|
//Add a default-highlighting for the passed text
|
|
*highlighting << QVariant(textFormatStart);
|
|
*highlighting << QVariant(ret.length() - textFormatStart);
|
|
*highlighting << boldFormat;
|
|
textFormatStart = ret.length();
|
|
}
|
|
|
|
bool first = true;
|
|
int num = 0;
|
|
foreach(Declaration* decl, parameters)
|
|
{
|
|
if (first)
|
|
first = false;
|
|
else
|
|
ret += ", ";
|
|
|
|
///@todo Find out whether it's class or another type
|
|
if(decl->abstractType() && !decl->type<CppTemplateParameterType>())
|
|
ret += decl->abstractType()->toString();
|
|
else
|
|
ret += "class";
|
|
|
|
ret += " ";
|
|
|
|
if( highlighting && ret.length() != textFormatStart )
|
|
{
|
|
*highlighting << QVariant(textFormatStart);
|
|
*highlighting << QVariant(ret.length() - textFormatStart);
|
|
*highlighting << normalFormat;
|
|
textFormatStart = ret.length();
|
|
}
|
|
|
|
ret += decl->identifier().toString();
|
|
|
|
if( highlighting && ret.length() != textFormatStart )
|
|
{
|
|
*highlighting << QVariant(textFormatStart);
|
|
*highlighting << QVariant(ret.length() - textFormatStart);
|
|
if(item.completionContext() && item.completionContext()->accessType() == Cpp::CodeCompletionContext::TemplateAccess && num == item.completionContext()->matchPosition())
|
|
*highlighting << highlightFormat;
|
|
else
|
|
*highlighting << normalFormat;
|
|
textFormatStart = ret.length();
|
|
}
|
|
|
|
TemplateParameterDeclaration* paramDecl = dynamic_cast<TemplateParameterDeclaration*>(decl);
|
|
if(!paramDecl->defaultParameter().isEmpty())
|
|
ret += " = " + paramDecl->defaultParameter().toString();
|
|
|
|
++num;
|
|
}
|
|
|
|
if( highlighting && ret.length() != textFormatStart )
|
|
{
|
|
*highlighting << QVariant(textFormatStart);
|
|
*highlighting << QVariant(ret.length() - textFormatStart);
|
|
*highlighting << normalFormat;
|
|
textFormatStart = ret.length();
|
|
}
|
|
|
|
ret += '>';
|
|
|
|
if( highlighting && ret.length() != textFormatStart )
|
|
{
|
|
*highlighting << QVariant(textFormatStart);
|
|
*highlighting << QVariant(ret.length() - textFormatStart);
|
|
*highlighting << boldFormat;
|
|
textFormatStart = ret.length();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//Returns the type as which a declaration in the completion-list should be interpreted, which especially means that it returns the return-type of a function.
|
|
AbstractType::Ptr effectiveType( const Declaration* decl )
|
|
{
|
|
if( !decl || !decl->abstractType() )
|
|
return AbstractType::Ptr();
|
|
|
|
if( decl->type<FunctionType>() )
|
|
return decl->type<FunctionType>()->returnType();
|
|
|
|
return decl->abstractType();
|
|
}
|
|
|
|
bool isSource(QString file) {
|
|
foreach(const QString& ext, CppUtils::sourceExtensions())
|
|
if(file.endsWith(ext))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
}
|