summaryrefslogtreecommitdiffstats
path: root/lib/cppparser/driver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/cppparser/driver.cpp')
-rw-r--r--lib/cppparser/driver.cpp965
1 files changed, 965 insertions, 0 deletions
diff --git a/lib/cppparser/driver.cpp b/lib/cppparser/driver.cpp
new file mode 100644
index 00000000..c5614d3e
--- /dev/null
+++ b/lib/cppparser/driver.cpp
@@ -0,0 +1,965 @@
+/* This file is part of KDevelop
+ Copyright (C) 2002,2003 Roberto Raggi <[email protected]>
+ Copyright (C) 2006 David Nolden <[email protected]>
+
+ This library 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 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., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#define CACHELEXER
+
+#include "driver.h"
+#include "lexer.h"
+#include "parser.h"
+#include <kdebug.h>
+#include <klocale.h>
+#include <stdlib.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qdir.h>
+#include <qdatastream.h>
+#include <qbuffer.h>
+#include <assert.h>
+
+#include <iostream>
+
+
+// void Macro::read( QDataStream& stream ) {
+// stream >> m_idHashValid;
+// stream >> m_valueHashValid;
+// stream >> m_idHash;
+// stream >> m_valueHash;
+// stream >> m_name;
+// stream >> m_body;
+// stream >> m_fileName;
+// stream >> m_hasArguments;
+// stream >> m_argumentList;
+// }
+//
+// void Macro::write( QDataStream& stream ) const {
+// stream << m_idHashValid;
+// stream << m_valueHashValid;
+// stream << m_idHash;
+// stream << m_valueHash;
+// stream << m_name;
+// stream << m_body;
+// stream << m_fileName;
+// stream << m_hasArguments;
+// stream << m_argumentList;
+// }
+
+
+class IntIncreaser {
+ public:
+ IntIncreaser( int& i ) : m_i( i ) {
+ ++m_i;
+ }
+ ~IntIncreaser() {
+ --m_i;
+ }
+ private:
+ int& m_i;
+};
+
+class DefaultSourceProvider: public SourceProvider {
+ public:
+ DefaultSourceProvider() {}
+
+ virtual QString contents( const QString& fileName ) {
+ QString source;
+
+ QFile f( fileName );
+ if ( f.open( IO_ReadOnly ) ) {
+ QTextStream s( &f );
+ source = s.read();
+ f.close();
+ }
+ return source;
+ }
+
+ virtual bool isModified( const QString& fileName ) {
+ Q_UNUSED( fileName );
+ return true;
+ }
+
+ private:
+ DefaultSourceProvider( const DefaultSourceProvider& source );
+ void operator = ( const DefaultSourceProvider& source );
+};
+
+
+Driver::Driver()
+ : depresolv( FALSE ), lexer( 0 ), m_lexerCache( this ), m_dependenceDepth( 0 ), m_maxDependenceDepth( 20 ) {
+ m_sourceProvider = new DefaultSourceProvider();
+}
+
+Driver::~Driver() {
+ reset();
+ delete m_sourceProvider;
+}
+
+void Driver::setMaxDependenceDepth( int depth ) {
+ m_maxDependenceDepth = depth;
+}
+
+SourceProvider* Driver::sourceProvider() {
+ return m_sourceProvider;
+}
+
+void Driver::setSourceProvider( SourceProvider* sourceProvider ) {
+ delete m_sourceProvider;
+ m_sourceProvider = sourceProvider;
+}
+
+void Driver::reset( ) {
+ m_lexerCache.clear();
+ m_dependences.clear();
+ m_macros.clear();
+ m_problems.clear();
+ m_includePaths.clear();
+
+ while ( m_parsedUnits.size() ) {
+ //TranslationUnitAST* unit = **m_parsedUnits.begin();
+ m_parsedUnits.remove( m_parsedUnits.begin() );
+ //delete( unit );
+ }
+}
+
+QStringList Driver::getCustomIncludePath( const QString& ) {
+ return includePaths();
+}
+
+void Driver::remove
+ ( const QString & fileName ) {
+ m_dependences.remove( fileName );
+ m_problems.remove( fileName );
+ if( !isResolveDependencesEnabled() )
+ removeAllMacrosInFile( fileName );
+
+ QMap<QString, ParsedFilePointer>::Iterator it = m_parsedUnits.find( fileName );
+ if ( it != m_parsedUnits.end() ) {
+ //TranslationUnitAST * unit = **it;
+ m_parsedUnits.remove( it );
+ //delete( unit );
+ }
+}
+
+void Driver::removeAllMacrosInFile( const QString& fileName ) {
+ MacroMap::iterator it = m_macros.begin();
+ while ( it != m_macros.end() ) {
+ Macro m = ( *it ).second;
+ if ( m.fileName() == fileName ) {
+ m_macros.erase( it++ );
+ } else {
+ ++it;
+ }
+ }
+}
+
+void Driver::usingString( const HashedString& str ) {
+ #ifdef CACHELEXER
+ if( m_currentLexerCache ) {
+ m_currentLexerCache->addString( m_lexerCache.unifyString( str ) );
+ }
+ #endif
+}
+
+bool Driver::hasMacro( const HashedString& name ) {
+ std::pair< MacroMap::const_iterator, MacroMap::const_iterator > range = m_macros.equal_range( name );
+ if ( range.first == range.second ) {
+ return false;
+ } else {
+ const Macro& m( ( *( --range.second ) ).second );
+ if ( m.isUndef() )
+ return false;
+ else
+ return true;
+ }
+ return false;
+}
+
+QString deepCopy( const QString& str ) {
+ return str;
+ //return str.ascii();
+}
+
+const Macro& Driver::macro( const HashedString& name ) const {
+ std::pair< MacroMap::const_iterator, MacroMap::const_iterator > range = m_macros.equal_range( name );
+ if ( range.first == range.second ) {
+ return ( *const_cast<MacroMap&>( m_macros ).insert( std::make_pair( deepCopy( name.str() ), Macro() ) ) ).second; ///Since we need to return a reference, there's no other way.
+ } else {
+ return ( *( --range.second ) ).second;
+ }
+}
+Macro& Driver::macro( const HashedString& name ) {
+ std::pair< MacroMap::iterator, MacroMap::iterator > range = m_macros.equal_range( name );
+ if ( range.first == range.second ) {
+ return ( *m_macros.insert( std::make_pair( deepCopy( name.str() ), Macro() ) ) ).second;
+ } else {
+ return ( *( --range.second ) ).second;
+ }
+}
+
+void Driver::addMacro( const Macro & macro ) {
+ std::pair< MacroMap::iterator, MacroMap::iterator > range = m_macros.equal_range( macro.name() );
+
+ if ( range.first == range.second ) {
+ m_macros.insert( std::make_pair( deepCopy( macro.name() ), macro ) );
+ } else {
+ ///Insert behind the other macros
+ m_macros.insert( range.second, std::make_pair( deepCopy( macro.name() ), macro ) );
+ Macro cp = this->macro( macro.name() );
+ assert( macro == cp );
+ }
+
+#ifdef CACHELEXER
+ if( m_currentLexerCache )
+ m_currentLexerCache->addDefinedMacro( macro );
+#endif
+}
+
+void Driver::removeMacro( const HashedString& macroName ) {
+ std::pair< MacroMap::iterator, MacroMap::iterator > range = m_macros.equal_range( macroName );
+ if ( range.first != range.second ) {
+ m_macros.erase( --range.second );
+ }
+}
+
+ParsedFilePointer Driver::takeTranslationUnit( const QString& fileName ) {
+ QMap<QString, ParsedFilePointer>::Iterator it = m_parsedUnits.find( fileName );
+ ParsedFilePointer unit( *it );
+ //m_parsedUnits.remove( it );
+ m_parsedUnits[ fileName ] = 0;
+ return unit;
+}
+
+void Driver::takeTranslationUnit( const ParsedFile& file ) {
+ QMap<QString, ParsedFilePointer>::Iterator it = m_parsedUnits.find( file.fileName() );
+ m_parsedUnits[ file.fileName() ] = 0;
+}
+
+ParsedFilePointer Driver::translationUnit( const QString& fileName ) const {
+ QMap<QString, ParsedFilePointer>::ConstIterator it = m_parsedUnits.find( fileName );
+ return it != m_parsedUnits.end() ? *it : 0;
+}
+
+class Driver::ParseHelper {
+ public:
+ ParseHelper( const QString& fileName, bool force, Driver* driver, bool reportMessages = true, QString includedFrom = QString() ) : m_wasReset( false ), m_fileName( fileName ), m_previousFileName( driver->m_currentFileName ), m_previousLexer( driver->lexer ), m_previousParsedFile( driver->m_currentParsedFile ), m_previousCachedLexedFile( driver->m_currentLexerCache ), m_force( force ), m_driver( driver ), m_lex( m_driver ) {
+ QFileInfo fileInfo( fileName );
+ m_driver->m_currentParsedFile = new ParsedFile( fileName, fileInfo.lastModified() );
+ if( !includedFrom.isEmpty() )
+ m_driver->m_currentParsedFile->setIncludedFrom( includedFrom );
+#ifdef CACHELEXER
+ m_driver->m_currentLexerCache = new CachedLexedFile( fileName, &m_driver->m_lexerCache );
+#endif
+ m_absFilePath = fileInfo.absFilePath();
+
+ QMap<QString, ParsedFilePointer>::Iterator it = m_driver->m_parsedUnits.find( m_absFilePath );
+
+ if ( force && it != m_driver->m_parsedUnits.end() ) {
+ m_driver->takeTranslationUnit( m_absFilePath );
+ } else if ( it != m_driver->m_parsedUnits.end() && *it != 0 ) {
+ // file already processed
+ return ;
+ }
+
+ CachedLexedFilePointer lexedFileP = m_driver->m_lexerCache.lexedFile( HashedString( fileName ) );
+
+ m_driver->m_dependences.remove( fileName );
+ m_driver->m_problems.remove( fileName );
+
+ driver->m_currentFileName = fileName;
+
+ m_driver->lexer = &m_lex;
+ m_driver->setupLexer( &m_lex );
+
+ m_lex.setReportMessages( reportMessages );
+
+ //kdDebug( 9007 ) << "lexing file " << fileName << endl;
+ m_lex.setSource( m_driver->sourceProvider() ->contents( fileName ) );
+ if(m_previousCachedLexedFile)
+ m_previousCachedLexedFile->merge( *m_driver->m_currentLexerCache );
+ else
+ m_driver->findOrInsertProblemList( m_driver->m_currentMasterFileName ) += m_driver->m_currentLexerCache->problems();
+
+ if( !lexedFileP && m_previousParsedFile ) //only add the new cache-instance if a fitting isn't already stored, and if this file was included by another one.
+ m_driver->m_lexerCache.addLexedFile( m_driver->m_currentLexerCache );
+
+ //Copy the recursive include-files into the ParsedFile
+ m_driver->m_currentParsedFile->addIncludeFiles( m_driver->m_currentLexerCache->includeFiles() );
+ m_driver->m_currentParsedFile->setSkippedLines( m_lex.skippedLines() );
+ }
+
+ void parse() {
+ QString oldMasterFileName = m_driver->m_currentMasterFileName; //Change the master-file so problems will be reported correctly
+ m_driver->m_currentMasterFileName = m_absFilePath;
+
+ CachedLexedFilePointer lf = m_driver->m_currentLexerCache; //Set the lexer-cache to zero, so the problems registered through addProblem go directly into the file
+ m_driver->m_currentLexerCache = 0;
+
+ Parser parser( m_driver, m_driver->lexer );
+ m_driver->setupParser( &parser );
+
+ TranslationUnitAST::Node unit;
+ parser.parseTranslationUnit( unit );
+ m_driver->m_currentParsedFile->setTranslationUnit( unit );
+ m_driver->m_parsedUnits.insert( m_fileName, m_driver->m_currentParsedFile );
+ m_driver->fileParsed( *m_driver->m_currentParsedFile );
+
+ m_driver->m_currentLexerCache = lf;
+
+ m_driver->m_currentMasterFileName = oldMasterFileName;
+ }
+
+ ParsedFilePointer parsedFile() const {
+ return m_driver->m_currentParsedFile;
+ }
+
+ void reset() {
+ if ( !m_wasReset ) {
+ m_driver->m_currentFileName = m_previousFileName;
+ m_driver->lexer = m_previousLexer;
+ m_driver->m_currentParsedFile = m_previousParsedFile;
+ m_driver->m_currentLexerCache = m_previousCachedLexedFile;
+ if( m_driver->m_currentLexerCache == 0 ) {
+
+ }
+
+ m_wasReset = true;
+ }
+ }
+
+ ~ParseHelper() {
+ reset();
+ }
+
+
+ private:
+ bool m_wasReset;
+ QString m_fileName;
+ QString m_absFilePath;
+ QString m_previousFileName;
+ Lexer* m_previousLexer;
+ ParsedFilePointer m_previousParsedFile;
+ CachedLexedFilePointer m_previousCachedLexedFile;
+ bool m_force;
+ Driver* m_driver;
+ Lexer m_lex;
+};
+
+
+void Driver::addDependence( const QString & fileName, const Dependence & dep ) {
+
+ // this can happen if the parser was invoked on a snippet of text and not a file
+ if ( fileName.isEmpty() || !m_currentParsedFile )
+ return;
+
+ //@todo prevent cyclic dependency-loops
+ QFileInfo fileInfo( dep.first );
+ QString fn = fileInfo.absFilePath();
+
+ if ( !depresolv ) {
+ findOrInsertDependenceList( fileName ).insert( fn, dep );
+ m_currentParsedFile->addIncludeFile( dep.first, 0, dep.second == Dep_Local );
+ return ;
+ }
+
+ QString file = findIncludeFile( dep );
+
+ findOrInsertDependenceList( fileName ).insert( file, dep );
+ m_currentParsedFile->addIncludeFile( file, 0, dep.second == Dep_Local );
+
+ if ( !QFile::exists( file ) ) {
+ Problem p( i18n( "Could not find include file %1" ).arg( dep.first ),
+ lexer ? lexer->currentLine() : -1,
+ lexer ? lexer->currentColumn() : -1, Problem::Level_Warning );
+ addProblem( fileName, p );
+ return ;
+ }
+
+ if( m_currentLexerCache )
+ m_currentLexerCache->addIncludeFile( file, QDateTime() ); ///The time will be overwritten in CachedLexedFile::merge(...)
+
+ /**What should be done:
+ * 1. Lex the file to get all the macros etc.
+ * 2. TODO: Check what previously set macros the file was affected by, and compare those macros to any previously parsed instances of this file.
+ * 2.1 If there is a parse-instance of the file where all macros that played a role had the same values, we do not need to reparse this file.
+ * 2.2 If there is no such fitting instance, the file needs to be parsed and put to the code-model.
+ *
+ * It'll be necessary to have multiple versions of one file in the code-model.
+ */
+
+ IntIncreaser i( m_dependenceDepth );
+ if( m_dependenceDepth > m_maxDependenceDepth ) {
+ //kdDebug( 9007 ) << "maximum dependence-depth of " << m_maxDependenceDepth << " was reached, " << fileName << " will not be processed" << endl;
+ return;
+ }
+
+ CachedLexedFilePointer lexedFileP = m_lexerCache.lexedFile( HashedString( file ) );
+ if( lexedFileP ) {
+ CachedLexedFile& lexedFile( *lexedFileP );
+ m_currentLexerCache->merge( lexedFile ); //The ParseHelper will will copy the include-files into the result later
+ for( MacroSet::Macros::const_iterator it = lexedFile.definedMacros().macros().begin(); it != lexedFile.definedMacros().macros().end(); ++it ) {
+ addMacro( (*it) );
+ }
+ ///@todo fill usingMacro(...)
+ return;
+ }
+
+ ParseHelper h( file, true, this, false, m_currentMasterFileName );
+
+ /*if ( m_parsedUnits.find(file) != m_parsedUnits.end() )
+ return;*/
+
+ if( shouldParseIncludedFile( m_currentParsedFile ) ) ///Until the ParseHelper is destroyed, m_currentParsedFile will stay the included file
+ h.parse();
+}
+
+void Driver::addProblem( const QString & fileName, const Problem & problem ) {
+ Problem p( problem );
+ p.setFileName( fileName );
+
+ if( m_currentLexerCache )
+ m_currentLexerCache->addProblem( p );
+ else
+ findOrInsertProblemList( m_currentMasterFileName ).append( problem );
+}
+
+QMap< QString, Dependence >& Driver::findOrInsertDependenceList( const QString & fileName ) {
+ QMap<QString, QMap<QString, Dependence> >::Iterator it = m_dependences.find( fileName );
+ if ( it != m_dependences.end() )
+ return it.data();
+
+ QMap<QString, Dependence> l;
+ m_dependences.insert( deepCopy( fileName ), l );
+ return m_dependences[ fileName ];
+}
+
+QValueList < Problem >& Driver::findOrInsertProblemList( const QString & fileName ) {
+ QMap<QString, QValueList<Problem> >::Iterator it = m_problems.find( fileName );
+ if ( it != m_problems.end() )
+ return it.data();
+
+ QValueList<Problem> l;
+ m_problems.insert( fileName, l );
+ return m_problems[ fileName ];
+}
+
+QMap< QString, Dependence > Driver::dependences( const QString & fileName ) const {
+ QMap<QString, QMap<QString, Dependence> >::ConstIterator it = m_dependences.find( fileName );
+ if ( it != m_dependences.end() )
+ return it.data();
+ return QMap<QString, Dependence>();
+}
+
+const Driver::MacroMap& Driver::macros() const {
+ return m_macros;
+}
+
+void Driver::insertMacros( const MacroSet& macros ) {
+ for( MacroSet::Macros::const_iterator it = macros.m_usedMacros.begin(); it != macros.m_usedMacros.end(); ++it ) {
+ addMacro( *it );
+ }
+}
+
+QValueList < Problem > Driver::problems( const QString & fileName ) const {
+ QMap<QString, QValueList<Problem> >::ConstIterator it = m_problems.find( fileName );
+ if ( it != m_problems.end() )
+ return it.data();
+ return QValueList<Problem>();
+}
+
+void Driver::clearMacros() {
+ m_macros.clear();
+}
+
+void Driver::clearParsedMacros() {
+ //Keep global macros
+ for( MacroMap::iterator it = m_macros.begin(); it != m_macros.end(); ) {
+ if( !(*it).second.fileName().isEmpty() ) {
+ m_macros.erase( it++ );
+ } else {
+ ++it;
+ }
+ }
+}
+
+void Driver::parseFile( const QString& fileName, bool onlyPreProcess, bool force , bool macrosGlobal )
+{
+ QString oldMasterFileName = m_currentMasterFileName;
+ m_currentMasterFileName = fileName;
+
+ //if( isResolveDependencesEnabled() )
+ clearParsedMacros(); ///Since everything will be re-lexed, we do not need any old macros
+
+ m_lexerCache.increaseFrame();
+
+ //Remove the problems now instead of in ParseHelper, because this way the problems reported by getCustomIncludePath(...) will not be discarded
+ m_problems.remove( fileName );
+
+ QStringList oldIncludePaths = m_includePaths;
+ m_includePaths = getCustomIncludePath( fileName );
+
+ ParseHelper p( fileName, force, this );
+ if( !onlyPreProcess ){
+ p.parse();
+ }
+ if( macrosGlobal ) {
+ for( MacroMap::iterator it = m_macros.begin(); it != m_macros.end(); ++it) {
+ if( (*it).second.fileName() == fileName ) {
+ (*it).second.setFileName( QString::null );
+ }
+ }
+ }
+
+ m_includePaths = oldIncludePaths;
+ m_currentMasterFileName = oldMasterFileName;
+}
+
+void Driver::setupLexer( Lexer * lexer ) {
+ // stl
+ lexer->addSkipWord( "__STL_BEGIN_NAMESPACE" );
+ lexer->addSkipWord( "__STL_END_NAMESPACE" );
+ lexer->addSkipWord( "__STL_BEGIN_RELOPS_NAMESPACE" );
+ lexer->addSkipWord( "__STL_END_RELOPS_NAMESPACE" );
+ lexer->addSkipWord( "__STL_TEMPLATE_NULL" );
+ lexer->addSkipWord( "__STL_TRY" );
+ lexer->addSkipWord( "__STL_UNWIND" );
+ lexer->addSkipWord( "__STL_NOTHROW" );
+ lexer->addSkipWord( "__STL_NULL_TMPL_ARGS" );
+ lexer->addSkipWord( "__STL_UNWIND", SkipWordAndArguments );
+ lexer->addSkipWord( "__GC_CONST" );
+ lexer->addSkipWord( "__HASH_ALLOC_INIT", SkipWordAndArguments );
+ lexer->addSkipWord( "__STL_DEFAULT_ALLOCATOR", SkipWordAndArguments, "T" );
+ lexer->addSkipWord( "__STL_MUTEX_INITIALIZER" );
+ lexer->addSkipWord( "__STL_NULL_TMPL_ARGS" );
+
+ // antlr
+ lexer->addSkipWord( "ANTLR_BEGIN_NAMESPACE", SkipWordAndArguments );
+ lexer->addSkipWord( "ANTLR_USE_NAMESPACE", SkipWordAndArguments );
+ lexer->addSkipWord( "ANTLR_USING_NAMESPACE", SkipWordAndArguments );
+ lexer->addSkipWord( "ANTLR_END_NAMESPACE" );
+ lexer->addSkipWord( "ANTLR_C_USING", SkipWordAndArguments );
+ lexer->addSkipWord( "ANTLR_API" );
+
+ // gnu
+ lexer->addSkipWord( "__extension__", SkipWordAndArguments );
+ lexer->addSkipWord( "__attribute__", SkipWordAndArguments );
+ lexer->addSkipWord( "__BEGIN_DECLS" );
+ lexer->addSkipWord( "__END_DECLS" );
+ lexer->addSkipWord( "__THROW" );
+ lexer->addSkipWord( "__restrict" );
+ lexer->addSkipWord( "__restrict__" );
+ lexer->addSkipWord( "__attribute_pure__" );
+ lexer->addSkipWord( "__attribute_malloc__" );
+ lexer->addSkipWord( "__attribute_format_strfmon__" );
+ lexer->addSkipWord( "__asm__", SkipWordAndArguments );
+ lexer->addSkipWord( "__devinit" );
+ lexer->addSkipWord( "__devinit__" );
+ lexer->addSkipWord( "__init" );
+ lexer->addSkipWord( "__init__" );
+ lexer->addSkipWord( "__signed" );
+ lexer->addSkipWord( "__signed__" );
+ lexer->addSkipWord( "__unsigned" );
+ lexer->addSkipWord( "__unsigned__" );
+ lexer->addSkipWord( "asmlinkage" );
+ lexer->addSkipWord( "____cacheline_aligned" );
+ lexer->addSkipWord( "__glibcpp_class_requires", SkipWordAndArguments );
+ lexer->addSkipWord( "__glibcpp_class2_requires", SkipWordAndArguments );
+ lexer->addSkipWord( "__glibcpp_class4_requires", SkipWordAndArguments );
+ lexer->addSkipWord( "__glibcpp_function_requires", SkipWordAndArguments );
+ lexer->addSkipWord( "restrict" );
+
+ lexer->addSkipWord( "__BEGIN_NAMESPACE_STD" );
+ lexer->addSkipWord( "__END_NAMESPACE_STD" );
+ lexer->addSkipWord( "__BEGIN_NAMESPACE_C99" );
+ lexer->addSkipWord( "__END_NAMESPACE_C99" );
+ lexer->addSkipWord( "__USING_NAMESPACE_STD", SkipWordAndArguments );
+
+ // kde
+ lexer->addSkipWord( "K_SYCOCATYPE", SkipWordAndArguments );
+ lexer->addSkipWord( "EXPORT_DOCKCLASS" );
+ lexer->addSkipWord( "K_EXPORT_COMPONENT_FACTORY", SkipWordAndArguments );
+ lexer->addSkipWord( "K_SYCOCAFACTORY", SkipWordAndArguments );
+ lexer->addSkipWord( "KDE_DEPRECATED" );
+
+ // qt
+ lexer->addSkipWord( "Q_OBJECT" );
+ lexer->addSkipWord( "Q_OVERRIDE", SkipWordAndArguments );
+ lexer->addSkipWord( "Q_ENUMS", SkipWordAndArguments );
+ lexer->addSkipWord( "Q_PROPERTY", SkipWordAndArguments );
+ lexer->addSkipWord( "Q_CLASSINFO", SkipWordAndArguments );
+ lexer->addSkipWord( "Q_SETS", SkipWordAndArguments );
+ lexer->addSkipWord( "Q_UNUSED", SkipWordAndArguments );
+ lexer->addSkipWord( "Q_CREATE_INSTANCE", SkipWordAndArguments );
+ lexer->addSkipWord( "Q_DUMMY_COMPARISON_OPERATOR", SkipWordAndArguments );
+ lexer->addSkipWord( "ACTIVATE_SIGNAL_WITH_PARAM", SkipWordAndArguments );
+ lexer->addSkipWord( "Q_INLINE_TEMPLATES" );
+ lexer->addSkipWord( "Q_TEMPLATE_EXTERN" );
+ lexer->addSkipWord( "Q_TYPENAME" );
+ lexer->addSkipWord( "Q_REFCOUNT" );
+ lexer->addSkipWord( "Q_EXPLICIT" );
+ lexer->addSkipWord( "QMAC_PASCAL" );
+ lexer->addSkipWord( "QT_STATIC_CONST" );
+ lexer->addSkipWord( "QT_STATIC_CONST_IMPL" );
+ lexer->addSkipWord( "QT_WIN_PAINTER_MEMBERS" );
+ lexer->addSkipWord( "QT_NC_MSGBOX" );
+ lexer->addSkipWord( "Q_VARIANT_AS", SkipWordAndArguments );
+ lexer->addSkipWord( "CALLBACK_CALL_TYPE" );
+
+ // qt4 [erbsland]
+ lexer->addSkipWord( "Q_DECLARE_FLAGS", SkipWordAndArguments );
+ lexer->addSkipWord( "Q_DECLARE_OPERATORS_FOR_FLAGS", SkipWordAndArguments );
+
+ // flex
+ lexer->addSkipWord( "yyconst" );
+ lexer->addSkipWord( "YY_RULE_SETUP" );
+ lexer->addSkipWord( "YY_BREAK" );
+ lexer->addSkipWord( "YY_RESTORE_YY_MORE_OFFSET" );
+
+ // gtk
+ lexer->addSkipWord( "G_BEGIN_DECLS" );
+ lexer->addSkipWord( "G_END_DECLS" );
+ lexer->addSkipWord( "G_GNUC_CONST" );
+ lexer->addSkipWord( "G_CONST_RETURN" );
+ lexer->addSkipWord( "GTKMAIN_C_VAR" );
+ lexer->addSkipWord( "GTKVAR" );
+ lexer->addSkipWord( "GDKVAR" );
+ lexer->addSkipWord( "G_GNUC_PRINTF", SkipWordAndArguments );
+
+ // windows
+ lexer->addSkipWord( "WINAPI" );
+ lexer->addSkipWord( "__stdcall" );
+ lexer->addSkipWord( "__cdecl" );
+ lexer->addSkipWord( "_cdecl" );
+ lexer->addSkipWord( "CALLBACK" );
+
+ // gcc extensions
+ if( !hasMacro( "__asm__" ) ) addMacro( Macro( "__asm__", "asm" ) );
+ if( !hasMacro( "__inline" ) ) addMacro( Macro( "__inline", "inline" ) );
+ if( !hasMacro( "__inline__" ) ) addMacro( Macro( "__inline__", "inline" ) );
+ if( !hasMacro( "__const" ) ) addMacro( Macro( "__const", "const" ) );
+ if( !hasMacro( "__const__" ) ) addMacro( Macro( "__const__", "const" ) );
+ if( !hasMacro( "__volatile__" ) ) addMacro( Macro( "__volatile__", "volatile" ) );
+ if( !hasMacro( "__complex__" ) ) addMacro( Macro( "__complex__", "" ) );
+}
+
+void Driver::setupParser( Parser * parser ) {
+ Q_UNUSED( parser );
+}
+
+void Driver::clearIncludePaths() {
+ m_includePaths.clear();
+}
+
+void Driver::addIncludePath( const QString &path ) {
+ if ( !path.stripWhiteSpace().isEmpty() )
+ m_includePaths << path;
+}
+
+QString Driver::findIncludeFile( const Dependence& dep, const QString& fromFile ) {
+ QString fileName = dep.first;
+
+ if ( dep.second == Dep_Local ) {
+ QString path = QFileInfo( fromFile ).dirPath( true );
+ QFileInfo fileInfo( QFileInfo( path, fileName ) );
+ if ( fileInfo.exists() && fileInfo.isFile() )
+ return fileInfo.absFilePath();
+ }
+
+ QStringList includePaths = getCustomIncludePath( fromFile );
+
+ for ( QStringList::ConstIterator it = includePaths.begin(); it != includePaths.end(); ++it ) {
+ QFileInfo fileInfo( *it, fileName );
+ if ( fileInfo.exists() && fileInfo.isFile() )
+ return fileInfo.absFilePath();
+ }
+
+ return QString::null;
+}
+
+QString Driver::findIncludeFile( const Dependence& dep ) const {
+ QString fileName = dep.first;
+
+ if ( dep.second == Dep_Local ) {
+ QString path = QFileInfo( currentFileName() ).dirPath( true );
+ QFileInfo fileInfo( QFileInfo( path, fileName ) );
+ if ( fileInfo.exists() && fileInfo.isFile() )
+ return fileInfo.absFilePath();
+ }
+
+ for ( QStringList::ConstIterator it = m_includePaths.begin(); it != m_includePaths.end(); ++it ) {
+ QFileInfo fileInfo( *it, fileName );
+ if ( fileInfo.exists() && fileInfo.isFile() )
+ return fileInfo.absFilePath();
+ }
+
+ return QString::null;
+}
+
+void Driver::setResolveDependencesEnabled( bool enabled ) {
+ depresolv = enabled;
+ if ( depresolv )
+ setupPreProcessor();
+}
+
+bool Driver::shouldParseIncludedFile( const ParsedFilePointer& /*file*/) {
+ return false;
+}
+
+void Driver::setupPreProcessor() {}
+
+void Driver::fileParsed( ParsedFile & fileName ) {
+ Q_UNUSED( fileName );
+}
+
+void Driver::usingMacro( const Macro& macro ) {
+ if( m_currentParsedFile )
+ m_currentParsedFile->usedMacros().addMacro( macro );
+#ifdef CACHELEXER
+ if( m_currentLexerCache )
+ m_currentLexerCache->addUsedMacro( macro );
+#endif
+}
+
+// void Macro::computeHash() const {
+// m_idHash = 7 * ( HashedString::hashString( m_name ) + m_argumentList.count() * 13 );
+// int a = 1;
+// m_idHash += 31 * m_argumentList.count();
+//
+// m_valueHash = 27 * ( HashedString::hashString( m_body ) + (m_isUndefMacro ? 1 : 0 ) );
+//
+// for( QValueList<Argument>::const_iterator it = m_argumentList.begin(); it != m_argumentList.end(); ++it ) {
+// a *= 19;
+// m_valueHash += a * HashedString::hashString( *it );
+// }
+// m_valueHashValid = true;
+// m_idHashValid = true;
+// }
+
+// MacroSet::MacroSet() : m_idHashValid( false ), m_valueHashValid( false ) {
+// }
+
+void MacroSet::addMacro( const Macro& macro ) {
+ std::pair<Macros::const_iterator, bool> r = m_usedMacros.insert( macro );
+ if( !r.second ) {
+ //Make sure the macro added later will be used
+ m_usedMacros.erase( r.first );
+ m_usedMacros.insert( macro );
+ }
+
+ m_idHashValid = m_valueHashValid = false;
+}
+
+void MacroSet::merge( const MacroSet& macros ) {
+ Macros m = macros.m_usedMacros; //Swap is needed so the merged macros take precedence
+ m.insert( m_usedMacros.begin(), m_usedMacros.end() );
+ m_usedMacros = m;
+ m_idHashValid = m_valueHashValid = false;
+}
+
+
+size_t MacroSet::idHash() const {
+ if( !m_idHashValid ) computeHash();
+ return m_idHash;
+}
+
+size_t MacroSet::valueHash() const {
+ if( !m_valueHashValid ) computeHash();
+ return m_valueHash;
+}
+
+void MacroSet::computeHash() const {
+ m_idHash = 0;
+ m_valueHash = 0;
+ int mult = 1;
+ for( Macros::const_iterator it = m_usedMacros.begin(); it != m_usedMacros.end(); ++it ) {
+ mult *= 31;
+ m_idHash += (*it).idHash();
+ m_valueHash += (*it).valueHash();
+ }
+}
+
+// void MacroSet::read( QDataStream& stream ) {
+// stream >> m_idHashValid >> m_idHash >> m_valueHashValid >> m_valueHash;
+// int cnt;
+// stream >> cnt;
+// m_usedMacros.clear();
+// Macro m;
+// for( int a = 0; a < cnt; a++ ) {
+// m.read( stream );
+// m_usedMacros.insert( m );
+// }
+// }
+//
+// void MacroSet::write( QDataStream& stream ) const {
+// stream << m_idHashValid << m_idHash << m_valueHashValid << m_valueHash;
+// stream << m_usedMacros.size();
+// for( Macros::const_iterator it = m_usedMacros.begin(); it != m_usedMacros.end(); ++it ) {
+// (*it).write( stream );
+// }
+// }
+
+/**
+ * @return All Macros that were used while processing this translation-unit
+ * */
+MacroSet& ParsedFile::usedMacros() {
+ return m_usedMacros;
+}
+
+const MacroSet& ParsedFile::usedMacros() const {
+ return m_usedMacros;
+}
+
+ParsedFile::ParsedFile( const QString& fileName, const QDateTime& timeStamp ) : m_translationUnit( 0 ), m_fileName( fileName ), m_timeStamp( timeStamp ) {
+ m_includeFiles.insert( fileName );
+}
+
+ParsedFile::ParsedFile( const QByteArray& array ) {
+ QBuffer b( array );
+ QDataStream d( &b );
+ read( d );
+}
+
+QString ParsedFile::includedFrom() const {
+ return m_includedFrom;
+}
+
+void ParsedFile::setIncludedFrom( const QString& str ) {
+ m_includedFrom = str;
+}
+
+QByteArray ParsedFile::serialize() const {
+ QByteArray array;
+ QBuffer b( array );
+ QDataStream d( &b );
+ write( d );
+ return array;
+}
+
+// void ParsedFile::read( QDataStream& stream ) {
+// int directIncludeFilesCount;
+// stream >> directIncludeFilesCount;
+// m_directIncludeFiles.clear();
+// for( int a = 0; a < directIncludeFilesCount; a++ ) {
+// IncludeDesc i;
+// stream >> i.local;
+// stream >> i.includePath;
+// //"parsed" will not be reconstructed
+// m_directIncludeFiles.push_back( i );
+// }
+// stream >> m_fileName;
+// stream >> m_timeStamp;
+// m_usedMacros.read( stream );
+// m_translationUnit = 0;
+// m_includeFiles.read( stream );
+// }
+//
+// void ParsedFile::write( QDataStream& stream ) const {
+// for( QValueList<IncludeDesc>::const_iterator it = m_directIncludeFiles.begin(); it != m_directIncludeFiles.end(); ++it ) {
+// stream << (*it).local;
+// stream << (*it).includePath;
+// }
+// stream << m_fileName;
+// stream << m_timeStamp;
+// m_usedMacros.write( stream );
+// m_includeFiles.write( stream );
+// }
+
+ParsedFile::operator TranslationUnitAST* () const {
+ if( !this ) return 0;
+ return m_translationUnit;
+}
+
+void ParsedFile::setTranslationUnit( const TranslationUnitAST::Node& trans ) {
+ m_translationUnit = trans;
+}
+
+// HashedStringSet& ParsedFile::includeFiles() {
+// return m_includeFiles;
+// }
+
+int ParsedFile::skippedLines() const {
+ return m_skippedLines;
+}
+
+void ParsedFile::setSkippedLines( int lines ) {
+ m_skippedLines = lines;
+}
+
+const HashedStringSet& ParsedFile::includeFiles() const {
+ return m_includeFiles;
+}
+
+QString ParsedFile::fileName() const {
+ return m_fileName;
+}
+
+QDateTime ParsedFile::timeStamp() const {
+ return m_timeStamp;
+}
+
+void ParsedFile::addIncludeFiles( const HashedStringSet& includeFiles ) {
+ m_includeFiles += includeFiles;
+}
+
+void ParsedFile::addIncludeFile( const QString& includePath, const ParsedFilePointer& parsed, bool localInclude ) {
+ m_includeFiles.insert( includePath );
+ if( parsed )
+ m_includeFiles += parsed->includeFiles();
+ IncludeDesc d;
+ d.local = localInclude;
+ d.includePath = includePath;
+ d.parsed = parsed;
+ m_directIncludeFiles << d;
+}
+
+const QValueList<ParsedFile::IncludeDesc>& ParsedFile::directIncludeFiles() const {
+ return m_directIncludeFiles;
+}
+
+bool MacroSet::hasMacro( const QString& name ) const {
+ Macros::const_iterator it = m_usedMacros.find( Macro( name, "" ) );
+ if( it != m_usedMacros.end() ) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool MacroSet::hasMacro( const HashedString& name ) const {
+ Macros::const_iterator it = m_usedMacros.find( Macro( name.str(), "" ) );
+ if( it != m_usedMacros.end() ) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+Macro MacroSet::macro( const QString& name ) const {
+ Macros::const_iterator it = m_usedMacros.find( Macro( name, "" ) );
+
+ if( it != m_usedMacros.end() ) {
+ return *it;
+ } else {
+ return Macro();
+ }
+}
+
+LexerCache* Driver::lexerCache() {
+ return &m_lexerCache;
+}
+