kde-extraapps/kdevelop/languages/cpp/cppduchain/expressionvisitor.h
2015-07-26 14:23:17 +03:00

359 lines
15 KiB
C++

/*
Copyright 2007 David Nolden <david.nolden.kdevelop@art-master.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef EXPRESSIONVISITOR_H
#define EXPRESSIONVISITOR_H
#include <language/duchain/types/abstracttype.h>
#include <language/duchain/declaration.h>
#include <language/duchain/problem.h>
#include "default_visitor.h"
#include "cppduchainexport.h"
#include "overloadresolution.h" /* needed for OverloadResover::Parameter */
#include "cpptypes.h"
namespace KDevelop {
class Declaration;
class DUContext;
class TopDUContext;
class Problem;
}
class Token;
namespace Cpp {
using namespace KDevelop;
/**
* \short A class which visits an expression and determines the type of the expression.
*
* \note A type-builder must have been run already over the ast.
*
* \todo The code is somewhat redundant with UseBuilder. Maybe UseBuilder should be based on this class. However a TypeBuilder must have been run already on the code, so the declarations of uses are located.
**/
class KDEVCPPDUCHAIN_EXPORT ExpressionVisitor : public DefaultVisitor {
public:
/**
* @param strict When this is false, the expression-visitor tries to recover from problems.
* For example when it cannot find a matching function, it returns the first of the candidates.
* @param propagateConstness When this is set to true, the expression visitor will propagate the constness
* in member accesses. Required for decltype support, i.e.:
* 'const A* a; decltype((a->x)) b;', here b should be const
* */
explicit ExpressionVisitor( ParseSession* session, const KDevelop::TopDUContext* source = 0,
bool strict = false, bool propagateConstness = false, bool mapAst = false );
~ExpressionVisitor();
struct Instance {
Instance() : isInstance(false) {
}
Instance( bool is ) : isInstance(is) {
}
Instance( DeclarationPointer decl ) : isInstance(true), declaration(decl) {
}
Instance( Declaration* decl ) : isInstance(true), declaration(DeclarationPointer(decl)) {
}
inline operator bool() const {
return isInstance;
}
bool isInstance;
DeclarationPointer declaration; //May contain the declaration of the instance, but only when isInstance is true. May also contain type-declaration, which signalizes that this is an instance of that type.
};
/**
* Will parse the tree and call expressionType(..) for each successfully evaluated type.
* A DelayedType is created for possible static expressions that use non-assigned template-arguments, so they can be re-evaluated later.
* @param ast the syntax-tree to evaluate. The context must already be built, the given AST needs to have a filled ducontext.
**/
void parse( AST* ast );
///Parses the qualification prefix of the given name
void parseNamePrefix( NameAST* ast );
AbstractType::Ptr lastType();
Instance lastInstance();
ParseSession* session();
void reportRealProblems(bool);
//Returns all posted real problems that appeared during this run. Only if reportRealProblems(true) has been called before.
QList<ProblemPointer> realProblems() const;
///Returns the last queried list of declarations
QList<DeclarationPointer> lastDeclarations() const;
protected:
/**
* Will be called for each relevant sub-node with the resolved type of that expression. This is not guaranteed to be called.
* There is also no guarantee in which order expressionType() will be called.
* The du-chain will not be locked in the moment this is called.
*
* @param node the AST-Node
* @param type the type the expression in the AST-node evaluates to
* @param instance If the expression evaluates to an instance of a type, this contains information about that instance. declaration is only filled for explicitly declared instances.
* If this is zero, the expression evaluates to a type.
*
* Warning:
* In case of temporary instances, decl will be the declaration of the basic type, not of an instance.
* Since temporary instances are never declared, there's no other way.
*
* examples:
* the expression "AbstractType::Ptr" evaluates to a type, so @param type would be filled and @param decl would be zero.
* When the context contains "AbstractType::Ptr ptr;", the expression "ptr" will evaluate to an instance of
* AbstractType::Ptr, so @param type will contain the type AbstractType::Ptr, and @param decl will point to the declaration of ptr.
*
* Problem:
**/
virtual void expressionType( AST* node, const AbstractType::Ptr& type, Instance instance ) {
Q_UNUSED(node) Q_UNUSED(type) Q_UNUSED(instance)
}
/** The duchain is not locked when this is called */
virtual void usingDeclaration( AST* node, size_t start_token, size_t end_token, const KDevelop::DeclarationPointer& decl ) {
Q_UNUSED(node) Q_UNUSED(start_token) Q_UNUSED(end_token) Q_UNUSED(decl)
}
/** Called when there is a problem, with a string for that problem.
* The default-implementation dumps all relevant information to
* kdDebug.
* @param node the node the problem is about
* @param str a string that describes the problem
*/
virtual void problem( AST* node, const QString& str );
/**
* Called for important issues in code.
*
* @see reportRealProblems()
*/
void realProblem( const ProblemPointer& problem );
const DUContext* currentContext() const;
const TopDUContext* topContext() const;
private:
bool m_strict, m_memberAccess, m_skipLastNamePart, m_mapAst;
AbstractType::Ptr m_lastType;
bool m_hadMemberAccess; // Whether during last call to findName() a class-member was accessed
Instance m_lastInstance; //Contains whether the last evaluation resulted in an instance, and maybe the instance-declaration
const KDevelop::TopDUContext* m_source;
//Whenever a list of declarations is queried, it is stored here. Especially in visitName(...) and findMember(...)
QList<DeclarationPointer> m_lastDeclarations;
//Here the parameters of function-calls are collected
//When a parameter could not be evaluated, this will hold a parameter with null-value type
QList<OverloadResolver::Parameter> m_parameters;
//One AST-node for each of the parameters in m_parameters
KDevVarLengthArray<AST*> m_parameterNodes;
int m_ignore_uses;
public:
/**
* Calls usingDeclaration(..) for any delayed uses, and registers a new use in m_currentUse.
* The whole sense of this thing is to allow updating an earlier created use in a later AST, like necessary because of overload-resolution.
* Must be called when the du-chain is not locked.
* */
void newUse( AST* node, size_t start_token, size_t end_token, const KDevelop::DeclarationPointer& decl ) {
if( !m_ignore_uses ) {
flushUse();
m_currentUse.isValid = true;
m_currentUse.node = node;
m_currentUse.start_token = start_token;
m_currentUse.end_token = end_token;
m_currentUse.declaration = decl;
}
}
protected:
const Token& tokenFromIndex( int index );
private:
///Fills m_parameters from the given argument-expression
///Returns true if all parameters could be evaluated successfully
bool buildParametersFromExpression(AST* expression);
bool buildParametersFromDeclaration(ParameterDeclarationClauseAST* paramDecl, bool store = true);
///If m_lastType is a valid constructed class-type, returns that type,
///and fills all its constructors into m_lastDeclarations
CppClassType::Ptr computeConstructedType();
void flushUse() {
if( m_currentUse.isValid )
usingDeclaration( m_currentUse.node, m_currentUse.start_token, m_currentUse.end_token, m_currentUse.declaration );
m_currentUse.isValid = false;
}
struct CurrentUse {
CurrentUse() : isValid(false), start_token(0), end_token(0) {
}
bool isValid;
AST* node;
size_t start_token, end_token;
KDevelop::DeclarationPointer declaration;
} m_currentUse; //This is used to temporarily delay the calling of usingDeclaration.
ParseSession* m_session;
const KDevelop::DUContext* m_currentContext;
const KDevelop::TopDUContext* m_topContext;
bool m_reportRealProblems;
QList<ProblemPointer> m_problems;
/// set to true when member access on a const object should result in a const type
/// i.e.: 'const A* a; decltype((a->x)) b;', here b should be const
bool m_propagateConstness;
inline void clearLast() {
m_lastInstance = Instance();
m_lastType = 0;
m_lastDeclarations.clear();
}
///Returns whether the given type and instance-info are an lvalue
bool isLValue( const AbstractType::Ptr& type, const Instance& instance );
///Creates a delayed type that refers to the expression within the given node. Sets the type as m_lastType
void createDelayedType( AST* node, bool expression = true );
/**
* Returns the dereferenced type(example: ReferenceType(PointerType) -> PointerType)
*
*
* !!DU-Chain must be locked!
* @return return-value will only be zero if m_lastType is zero
*/
AbstractType::Ptr realLastType() const;
/**
* Dereferences m_lastType if it is a pointer-type, else returns false.
*
* !!DU-Chain must be locked!
* */
bool dereferenceLastPointer();
/**
* m_lastType must be a pointer. It will be dereferenced in m_lastType,
* and m_lastDeclaration filled appropriately.
*
* !!DU-Chain must be locked!
*
* @param node Node shown while reporting problems
* @param constant will be set to true if something constant is dereferenced
* @return false on fail(for example type is no pointer)
*/
bool getPointerTarget( AST* node, bool* constant = 0 );
/**
* !!DU-Chain must be locked!
* Note that this may return zero even when base is valid, it needs to be an instance of IdentifiedType to be able to retrieve a declaration.
**/
Declaration* getDeclaration( const AbstractType::Ptr& base );
/**
* m_lastType must be a function.
* Return-value will be extracted, m_lastType and m_lastDeclaration
* filled appropriately.
*
* On failure, m_lastType will be 0.
*
* !!DU-Chain must be locked!
*
* @param node Node shown while reporting problems
* @return false on fail(for example type is no function)
*/
void getReturnValue( AST* node );
/** If the member was found, it is returned through m_lastType and m_lastDeclaration. On fail those are zero.
* du-chain must not be locked.
* @param node that issues the command. Only used for posting problems.
* @param type The structure the member should be searched in
* @param member Identifier of the member to search
* @param isConst Whether the type inherits const-ness from above
* @param postError whether a problem should be posted when the member is not found
*/
void findMember( AST* node, AbstractType::Ptr type, const Identifier& member, bool isConst = false, bool postProblem = true );
/**
* Visits post-fix sub-expressions.
* m_lastType and m_lastDeclaration must be filled with the types where to start.
* When the evaluation is successful, expressionType(..) is called with the resulting type.
* @param node The basic AST-node which will only be used for reporting problems
* @param nodes the nodes to visit
**/
void visitSubExpressions( AST* node, const ListNode<ExpressionAST*>* nodes );
void visitTypeSpecifier(TypeSpecifierAST*);
virtual void visitBinaryExpression(BinaryExpressionAST *) ;
virtual void visitCastExpression(CastExpressionAST *) ;
virtual void visitClassMemberAccess(ClassMemberAccessAST *) ;
virtual void visitCompoundStatement(CompoundStatementAST *) ;
virtual void visitCondition(ConditionAST *) ;
virtual void visitConditionalExpression(ConditionalExpressionAST *) ;
virtual void visitCppCastExpression(CppCastExpressionAST *) ;
virtual void visitDeclarationStatement(DeclarationStatementAST *) ;
virtual void visitDeclarator(DeclaratorAST *) ;
virtual void visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *) ;
virtual void visitExpressionOrDeclarationStatement(ExpressionOrDeclarationStatementAST *) ;
virtual void visitExpressionStatement(ExpressionStatementAST *) ;
virtual void visitFunctionCall(FunctionCallAST *) ;
virtual void visitIncrDecrExpression(IncrDecrExpressionAST *) ;
virtual void visitInitDeclarator(InitDeclaratorAST *) ;
virtual void visitInitializerClause(InitializerClauseAST *);
virtual void visitMemInitializer(MemInitializerAST *) ;
virtual void visitName(NameAST *) ;
virtual void visitNewDeclarator(NewDeclaratorAST *) ;
virtual void visitNewExpression(NewExpressionAST *) ;
virtual void visitPostfixExpression(PostfixExpressionAST *) ;
virtual void visitPrimaryExpression(PrimaryExpressionAST *) ;
virtual void visitPtrOperator(PtrOperatorAST *) ;
virtual void visitSimpleDeclaration(SimpleDeclarationAST *) ;
virtual void visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *) ;
virtual void visitSizeofExpression(SizeofExpressionAST *) ;
virtual void visitStringLiteral(StringLiteralAST *) ;
virtual void visitSubscriptExpression(SubscriptExpressionAST *) ;
virtual void visitTranslationUnit(TranslationUnitAST *) ;
virtual void visitTypeId(TypeIdAST *) ;
virtual void visitUnaryExpression(UnaryExpressionAST *) ;
virtual void visitSignalSlotExpression (SignalSlotExpressionAST*);
virtual void visitTypeIDOperator(TypeIDOperatorAST *);
virtual void visitLambdaExpression(LambdaExpressionAST *);
virtual void visitBracedInitList(BracedInitListAST *);
virtual void visit(AST* node);
void visitExpressionToken(uint tokenIndex, AST* node);
void putStringType();
AbstractType::Ptr qObjectPtrType() const;
///Visits all nodes, and resets m_lastType and m_lastDeclaration to the previous values before each visit so they cannot influence each other
template <class _Tp>
void visitIndependentNodes(const ListNode<_Tp> *nodes);
private:
void handleFunctionCallOrInit(AST* node, ExpressionAST* arguments);
bool m_handlingFunctionCallOrInit;
};
}
#endif