Skip to content

Commit

Permalink
Avoid crash with represent_value exp function
Browse files Browse the repository at this point in the history
represent_value would crash when it was called via evaluate without any context specified.
  • Loading branch information
m-kuhn committed Dec 27, 2017
1 parent a4141c7 commit d01f94f
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 28 deletions.
64 changes: 36 additions & 28 deletions src/core/expression/qgsexpressionfunction.cpp
Expand Up @@ -3446,42 +3446,50 @@ static QVariant fcnRepresentValue( const QVariantList &values, const QgsExpressi
{
QVariant result;
QString fieldName;
if ( !values.isEmpty() )
{
QgsExpressionNodeColumnRef *col = dynamic_cast<QgsExpressionNodeColumnRef *>( node->args()->at( 0 ) );
if ( col && ( values.size() == 1 || !values.at( 1 ).isValid() ) )
fieldName = col->name();
else if ( values.size() == 2 )
fieldName = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
}

QVariant value = values.at( 0 );

const QgsFields fields = context->fields();
int fieldIndex = fields.lookupField( fieldName );

if ( fieldIndex == -1 )
{
parent->setEvalErrorString( QCoreApplication::translate( "expression", "%1: Field not found %2" ).arg( QStringLiteral( "represent_value" ), fieldName ) );
}
else
if ( context )
{
QgsVectorLayer *layer = QgsExpressionUtils::getVectorLayer( context->variable( "layer" ), parent );
const QgsEditorWidgetSetup setup = fields.at( fieldIndex ).editorWidgetSetup();
const QgsFieldFormatter *formatter = QgsApplication::fieldFormatterRegistry()->fieldFormatter( setup.type() );
if ( !values.isEmpty() )
{
QgsExpressionNodeColumnRef *col = dynamic_cast<QgsExpressionNodeColumnRef *>( node->args()->at( 0 ) );
if ( col && ( values.size() == 1 || !values.at( 1 ).isValid() ) )
fieldName = col->name();
else if ( values.size() == 2 )
fieldName = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
}

const QString cacheKey = QStringLiteral( "repvalfcn:%1:%2" ).arg( layer ? layer->id() : QStringLiteral( "[None]" ), fieldName );
QVariant value = values.at( 0 );

QVariant cache;
if ( !context->hasCachedValue( cacheKey ) )
const QgsFields fields = context->fields();
int fieldIndex = fields.lookupField( fieldName );

if ( fieldIndex == -1 )
{
cache = formatter->createCache( layer, fieldIndex, setup.config() );
context->setCachedValue( cacheKey, cache );
parent->setEvalErrorString( QCoreApplication::translate( "expression", "%1: Field not found %2" ).arg( QStringLiteral( "represent_value" ), fieldName ) );
}
else
cache = context->cachedValue( cacheKey );
{
QgsVectorLayer *layer = QgsExpressionUtils::getVectorLayer( context->variable( "layer" ), parent );
const QgsEditorWidgetSetup setup = fields.at( fieldIndex ).editorWidgetSetup();
const QgsFieldFormatter *formatter = QgsApplication::fieldFormatterRegistry()->fieldFormatter( setup.type() );

const QString cacheKey = QStringLiteral( "repvalfcn:%1:%2" ).arg( layer ? layer->id() : QStringLiteral( "[None]" ), fieldName );

result = formatter->representValue( layer, fieldIndex, setup.config(), cache, value );
QVariant cache;
if ( !context->hasCachedValue( cacheKey ) )
{
cache = formatter->createCache( layer, fieldIndex, setup.config() );
context->setCachedValue( cacheKey, cache );
}
else
cache = context->cachedValue( cacheKey );

result = formatter->representValue( layer, fieldIndex, setup.config(), cache, value );
}
}
else
{
parent->setEvalErrorString( QCoreApplication::translate( "expression", "%1: function cannot be evaluated without a context." ).arg( QStringLiteral( "represent_value" ), fieldName ) );
}

return result;
Expand Down
9 changes: 9 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -429,6 +429,15 @@ class TestQgsExpression: public QObject
QCOMPARE( expression.evaluate( &context ).toString(), QStringLiteral( "one" ) );

QgsExpression expression4( "represent_value('Class')" );
expression4.evaluate();
if ( expression4.hasParserError() )
qDebug() << expression4.parserErrorString();
QVERIFY( !expression4.hasParserError() );
if ( expression4.hasEvalError() )
qDebug() << expression4.evalErrorString();
QVERIFY( expression4.hasEvalError() );

expression4.prepare( &context );
if ( expression4.hasParserError() )
qDebug() << expression4.parserErrorString();
QVERIFY( !expression4.hasParserError() );
Expand Down

0 comments on commit d01f94f

Please sign in to comment.