/* * KDevelop C++ Code Completion Support * * Copyright 2007-2008 David Nolden * * 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 #include #include #include #include #include #include "../cppduchain/cpptypes.h" #include "../cppduchain/cppduchain.h" #include "../cppduchain/overloadresolutionhelper.h" #include "../cppduchain/viablefunctions.h" #include #include #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* 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(dec); FunctionType::Ptr functionType = dec->type(); if (functionType && decl) { QVector parameters; if( DUChainUtils::getArgumentContext(dec) ) parameters = DUChainUtils::getArgumentContext(dec)->localDeclarations(ctx ? ctx->topContext() : 0); // QStringList defaultParams = decl->defaultParameters(); QVector::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& 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())) { 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 += ""; 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* 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(dec)); if(!tempDecl) return; DUContext* templateContext = tempDecl->templateContext( dec->topContext() ); if(!templateContext) return; QVector 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()) 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(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() ) return decl->type()->returnType(); return decl->abstractType(); } bool isSource(QString file) { foreach(const QString& ext, CppUtils::sourceExtensions()) if(file.endsWith(ext)) return true; return false; } }