From kde-commits Wed Oct 31 23:57:36 2007 From: David Nolden Date: Wed, 31 Oct 2007 23:57:36 +0000 To: kde-commits Subject: KDE/kdevelop/languages/cpp Message-Id: <1193875056.004977.15539.nullmailer () svn ! kde ! org> X-MARC-Message: https://marc.info/?l=kde-commits&m=119387506429403 SVN commit 731547 by zwabel: Preprocess all text used for completion using the stored macros. This results in better argument-matching and argument-hints for functions renamed using #define. M +81 -14 codecompletioncontext.cpp M +3 -2 codecompletioncontext.h --- trunk/KDE/kdevelop/languages/cpp/codecompletioncontext.cpp #731546:731547 @@ -28,12 +28,26 @@ #include "cppduchain/typeutils.h" #include "cppduchain/overloadresolution.h" #include "cppduchain/viablefunctions.h" +#include "cppduchain/environmentmanager.h" #include "cpptypes.h" #include "safetycounter.h" #include "cpplanguagesupport.h" +#include "parser/rpp/pp-engine.h" +#include "parser/rpp/preprocessor.h" +#include "parser/rpp/pp-environment.h" +#include "parser/rpp/pp-macro.h" +#include "parser/problem.h" #define LOCKDUCHAIN DUChainReadLocker lock(DUChain::lock()) +//#define DEBUG + +#ifdef DEBUG +#define ifDebug(x) x +#else +#define ifDebug(x) +#endif + using namespace Cpp; using namespace KDevelop; @@ -54,6 +68,51 @@ typedef PushValue IntPusher; +/** + * Preprocess the given string using the macros from given EnvironmentFile up to the given line + * If line is -1, all macros are respected. + * This is a quite slow operation, because thousands of macros need to be shuffled around. + * + * @todo maybe implement a version of rpp::Environment that directly works on EnvironmentFile, + * without needing to copy all macros. + * */ +QString preprocess( const QString& text, const Cpp::EnvironmentFilePointer& file, int line ) { + + rpp::Preprocessor preprocessor; + rpp::pp pp(&preprocessor); + + { + LOCKDUCHAIN; +/* kDebug() << "defined macros: " << file->definedMacros().size();*/ + //Copy in all macros from the file + for( MacroSet::Macros::const_iterator it = file->definedMacros().macros().begin(); it != file->definedMacros().macros().end(); ++it ) { + if( line == -1 || line > (*it).sourceLine || !(file->url().equals( KUrl((*it).file) ) ) ) { + pp.environment()->setMacro( new rpp::pp_macro( *it ) ); +/* kDebug() << "adding macro " << (*it).name.str();*/ + } else { +/* kDebug() << "leaving macro " << (*it).name.str();*/ + } + } +/* kDebug() << "used macros: " << file->usedMacros().size();*/ + for( MacroSet::Macros::const_iterator it = file->usedMacros().macros().begin(); it != file->usedMacros().macros().end(); ++it ) { + if( line == -1 || line > (*it).sourceLine || !(file->url().equals( KUrl((*it).file) ) ) ) { + pp.environment()->setMacro( new rpp::pp_macro( *it ) ); +/* kDebug() << "adding macro " << (*it).name.str();*/ + } else { +/* kDebug() << "leaving macro " << (*it).name.str();*/ + } + } + } + + kDebug() << "text before preprocessing: " << text; + QString ret = pp.processFile("anonymous", rpp::pp::Data, text); + kDebug() << "text after preprocessing: " << ret; + pp.environment()->cleanup(); + + return ret; +} + +///Extracts the last line from the given string QString extractLastLine(const QString& str) { int prevLineEnd = str.lastIndexOf('\n'); if(prevLineEnd != -1) @@ -72,7 +131,7 @@ int completionRecursionDepth = 0; -CodeCompletionContext::CodeCompletionContext(DUContextPointer context, const QString& text, int depth, const QStringList& knownArgumentExpressions ) : m_memberAccessOperation(NoMemberAccess), m_valid(true), m_text(text), m_depth(depth), m_knownArgumentExpressions(knownArgumentExpressions), m_duContext(context), m_contextType(Normal), m_parentContext(0) +CodeCompletionContext::CodeCompletionContext(DUContextPointer context, const QString& text, int depth, const QStringList& knownArgumentExpressions, int line ) : m_memberAccessOperation(NoMemberAccess), m_valid(true), m_text(text), m_depth(depth), m_knownArgumentExpressions(knownArgumentExpressions), m_duContext(context), m_contextType(Normal), m_parentContext(0) { IntPusher( completionRecursionDepth, completionRecursionDepth+1 ); @@ -104,14 +163,14 @@ return; } - //log( "non-processed text: " + m_text ); - preprocessText(); + ifDebug( log( "non-processed text: " + m_text ); ) + preprocessText( line ); - m_text = Utils::clearComments( m_text ); - m_text = Utils::clearStrings( m_text ); - m_text = Utils::stripFinalWhitespace( m_text ); + m_text = Utils::clearComments( m_text ); + m_text = Utils::clearStrings( m_text ); + m_text = Utils::stripFinalWhitespace( m_text ); - //log( "processed text: " + m_text ); + ifDebug( log( "processed text: " + m_text ); ) ///@todo template-parameters @@ -189,11 +248,11 @@ int start_expr = Utils::expressionAt( m_text, m_text.length() ); m_expression = m_text.mid(start_expr).trimmed(); - - kDebug() << start_expr << " found expression: " << m_expression << " in text: " << m_text; QString expressionPrefix = Utils::stripFinalWhitespace( m_text.left(start_expr) ); + ifDebug( log( "expressionPrefix: " + expressionPrefix ); ) + ///Handle recursive contexts(Example: "ret = function1(param1, function2(" ) if( expressionPrefix.endsWith('(') || expressionPrefix.endsWith(',') ) { log( QString("Recursive function-call: Searching parent-context in \"%1\"").arg(expressionPrefix) ); @@ -202,6 +261,7 @@ //Find out which argument-number this expression is, and compute the beginning of the parent function-call(parentContextLast) QStringList otherArguments; int parentContextEnd = expressionPrefix.length(); + Utils::skipFunctionArguments( expressionPrefix, otherArguments, parentContextEnd ); QString parentContextText = expressionPrefix.left(parentContextEnd); @@ -235,12 +295,13 @@ expr = expr.right( expr.length() - 5 ); } - ExpressionParser expressionParser; + ExpressionParser expressionParser/*(false, true)*/; - kDebug() << "expression: " << expr; + ifDebug( kDebug() << "expression: " << expr; ) if( !expr.trimmed().isEmpty() ) { m_expressionResult = expressionParser.evaluateType( expr.toUtf8(), m_duContext ); + ifDebug( kDebug() << "expression result: " << m_expressionResult.toString(); ) if( !m_expressionResult.isValid() ) { if( m_memberAccessOperation != StaticMemberChoose ) { log( QString("expression \"%1\" could not be evaluated").arg(expr) ); @@ -489,9 +550,15 @@ return ret; } -void CodeCompletionContext::preprocessText() { - ///@todo implement, preprocess m_text in m_duContext at m_position - ///All macros can be found in the context's EnvironmentFile, in definedMacros() together with usedMacros() +void CodeCompletionContext::preprocessText( int line ) { + + LOCKDUCHAIN; + + if( m_duContext ) { + m_text = preprocess( m_text, Cpp::EnvironmentFilePointer( dynamic_cast(m_duContext->topContext()->parsingEnvironmentFile().data()) ), line ); + }else{ + kWarning() << "error: no ducontext"; + } } CodeCompletionContext::MemberAccessOperation CodeCompletionContext::memberAccessOperation() const { --- trunk/KDE/kdevelop/languages/cpp/codecompletioncontext.h #731546:731547 @@ -82,8 +82,9 @@ * @param text the text to analyze. It usually is the text in the range starting at the beginning of the context, and ending at the position where completion should start * @warning The du-chain must be unlocked when this is called * @param knownArgumentExpressions has no effect when firstContext is set + * @param line Optional line that will be used to filter the macros * */ - CodeCompletionContext(KDevelop::DUContextPointer context, const QString& text, int depth = 0, const QStringList& knownArgumentExpressions = QStringList() ); + CodeCompletionContext(KDevelop::DUContextPointer context, const QString& text, int depth = 0, const QStringList& knownArgumentExpressions = QStringList(), int line = -1 ); ~CodeCompletionContext(); ///@return whether this context is valid for code-completion @@ -158,7 +159,7 @@ ///Returns whether the end of m_text is a valid completion-position bool isValidPosition(); ///Should preprocess the given text(replace macros with their body etc.) - void preprocessText(); + void preprocessText( int line ); void processIncludeDirective(QString line); void log( const QString& str ) const; ///Returns whether the given strings ends with an overloaded operator that can form a parent-context