///////////////////////////////////////////////////////////////////////////// // Name: xmlparser.h // Purpose: Parser of the API/interface XML files // Author: Francesco Montorsi // Created: 2008/03/17 // RCS-ID: $Id$ // Copyright: (c) 2008 Francesco Montorsi // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// #ifndef _XMLPARSER_H_ #define _XMLPARSER_H_ #include #include #include #include /* IMPORTANT ========= Any fix aimed to reduce "false positives" which involves references to a specific wxWidgets class is marked in ifacecheck sources with the string: // ADHOC-FIX: // ...fix description... */ // helper macros #define LogMessage(fmt, ...) { if (g_bLogEnabled) { wxPrintf(fmt "\n", __VA_ARGS__); fflush(stdout); }} #define LogWarning(fmt, ...) { if (g_bLogEnabled) { wxPrintf(fmt "\n", __VA_ARGS__); fflush(stdout); }} #define LogError(fmt, ...) { if (g_bLogEnabled) { wxPrintf("ERROR: " fmt "\n", __VA_ARGS__); fflush(stdout); }} #define wxPrint(str) { wxPrintf(str); fflush(stdout); } // enable/disable logging extern bool g_bLogEnabled; class LogNull { public: LogNull() { g_bLogEnabled = false; } ~LogNull() { g_bLogEnabled = true; } }; // ---------------------------------------------------------------------------- // Represents a type with or without const/static/ qualifier // and with or without & and * operators // ---------------------------------------------------------------------------- class wxType { public: wxType() {} wxType(const wxString& type) { SetTypeFromString(type); } void SetTypeFromString(const wxString& t); wxString GetAsString() const { return m_strType; } // returns this type _without_ any decoration, // including the & (which indicates this is a reference), // the * (which indicates this is a pointer), etc. wxString GetAsCleanString() const { return m_strTypeClean; } bool IsConst() const { return m_strType.Contains("const"); } bool IsStatic() const { return m_strType.Contains("static"); } bool IsPointer() const { return m_strType.Contains("*"); } bool IsReference() const { return m_strType.Contains("&"); } bool operator==(const wxType& m) const; bool operator!=(const wxType& m) const { return !(*this == m); } bool IsOk() const; protected: wxString m_strType, m_strTypeClean; // m_strType "cleaned" of its attributes // (only for internal use) }; extern wxType wxEmptyType; WX_DECLARE_OBJARRAY(wxType, wxTypeArray); // ---------------------------------------------------------------------------- // Represents a type used as argument for some wxMethod // ---------------------------------------------------------------------------- class wxArgumentType : public wxType { public: wxArgumentType() {} wxArgumentType(const wxString& type, const wxString& defVal, const wxString& argName = wxEmptyString) { SetTypeFromString(type); SetDefaultValue(defVal); m_strArgName = argName; } void SetArgumentName(const wxString& name) { m_strArgName=name.Strip(wxString::both); } wxString GetArgumentName() const { return m_strArgName; } void SetDefaultValue(const wxString& defval, const wxString& defvalForCmp = wxEmptyString); wxString GetDefaultValue() const { return m_strDefaultValue; } // returns the default value used for comparisons wxString GetDefaultCleanValue() const { return m_strDefaultValueForCmp; } bool HasDefaultValue() const { return !m_strDefaultValue.IsEmpty(); } bool operator==(const wxArgumentType& m) const; bool operator!=(const wxArgumentType& m) const { return !(*this == m); } protected: wxString m_strDefaultValue; // this string may differ from m_strDefaultValue if there were // preprocessor substitutions or other "replacements" done to // avoid false errors. wxString m_strDefaultValueForCmp; // the argument name wxString m_strArgName; }; extern wxArgumentType wxEmptyArgumentType; WX_DECLARE_OBJARRAY(wxArgumentType, wxArgumentTypeArray); enum wxMethodAccessSpecifier { wxMAS_PUBLIC, wxMAS_PROTECTED, wxMAS_PRIVATE }; // ---------------------------------------------------------------------------- // Represents a single prototype of a class' member. // ---------------------------------------------------------------------------- class wxMethod { public: wxMethod() { m_bConst=m_bVirtual=m_bPureVirtual=m_bStatic=m_bDeprecated=false; m_nLine=-1; m_nAvailability=wxPORT_UNKNOWN; m_access=wxMAS_PUBLIC; } wxMethod(const wxType& rettype, const wxString& name, const wxArgumentTypeArray& arguments, bool isConst, bool isStatic, bool isVirtual) : m_retType(rettype), m_strName(name.Strip(wxString::both)), m_bConst(isConst), m_bStatic(isStatic), m_bVirtual(isVirtual) { SetArgumentTypes(arguments); m_nLine=-1; } public: // getters // bWithArgumentNames = output argument names? // bCleanDefaultValues = output clean argument default values? // bDeprecated = output [deprecated] next to deprecated methods? // bAccessSpec = output [public], [protected] or [private] next to method? // // TODO: convert to readable flags this set of bools wxString GetAsString(bool bWithArgumentNames = true, bool bCleanDefaultValues = false, bool bDeprecated = false, bool bAccessSpec = false) const; // parser of the prototype: // all these functions return strings with spaces stripped wxType GetReturnType() const { return m_retType; } wxString GetName() const { return m_strName; } const wxArgumentTypeArray& GetArgumentTypes() const { return m_args; } wxArgumentTypeArray& GetArgumentTypes() { return m_args; } int GetLocation() const { return m_nLine; } int GetAvailability() const { return m_nAvailability; } wxMethodAccessSpecifier GetAccessSpecifier() const { return m_access; } bool IsConst() const { return m_bConst; } bool IsStatic() const { return m_bStatic; } bool IsVirtual() const { return m_bVirtual; } bool IsPureVirtual() const { return m_bPureVirtual; } bool IsOk() const; bool IsCtor() const { return m_retType==wxEmptyType && !m_strName.StartsWith("~"); } bool IsDtor() const { return m_retType==wxEmptyType && m_strName.StartsWith("~"); } bool IsOperator() const { return m_strName.StartsWith("operator"); } bool IsDeprecated() const { return m_bDeprecated; } public: // setters void SetReturnType(const wxType& t) { m_retType=t; } void SetName(const wxString& name) { m_strName=name; } void SetArgumentTypes(const wxArgumentTypeArray& arr) { m_args=arr; } void SetConst(bool c = true) { m_bConst=c; } void SetStatic(bool c = true) { m_bStatic=c; } void SetVirtual(bool c = true) { m_bVirtual=c; } void SetPureVirtual(bool c = true) { m_bPureVirtual=c; if (c) m_bVirtual=c; // pure virtual => virtual } void SetDeprecated(bool c = true) { m_bDeprecated=c; } void SetLocation(int lineNumber) { m_nLine=lineNumber; } void SetAvailability(int nAvail) { m_nAvailability=nAvail; } void SetAccessSpecifier(wxMethodAccessSpecifier spec) { m_access=spec; } public: // misc bool operator==(const wxMethod&) const; bool operator!=(const wxMethod& m) const { return !(*this == m); } // this function works like operator== but tests everything: // - method name // - return type // - argument types // except for the method attributes (const,static,virtual,pureVirtual,deprecated) bool MatchesExceptForAttributes(const wxMethod& m) const; // returns true if this is a ctor which has default values for all its // argument, thus is able to act also as default ctor bool ActsAsDefaultCtor() const; // dumps the contents of this class in the given stream void Dump(wxTextOutputStream& stream) const; protected: wxType m_retType; wxString m_strName; wxArgumentTypeArray m_args; // misc attributes: bool m_bConst; bool m_bStatic; bool m_bVirtual; bool m_bPureVirtual; bool m_bDeprecated; // m_nLine can be -1 if no location infos are available int m_nLine; // this is a combination of wxPORT_* flags (see wxPortId) or wxPORT_UNKNOWN // if this method should be available for all wxWidgets ports. // NOTE: this is not used for comparing wxMethod objects // (gccXML never gives this kind of info). int m_nAvailability; // the access specifier for this method wxMethodAccessSpecifier m_access; }; WX_DECLARE_OBJARRAY(wxMethod, wxMethodArray); WX_DEFINE_ARRAY(const wxMethod*, wxMethodPtrArray); // we need wxClassPtrArray to be defined _before_ wxClass itself, // since wxClass uses wxClassPtrArray. class wxClass; WX_DEFINE_ARRAY(const wxClass*, wxClassPtrArray); class wxXmlInterface; // ---------------------------------------------------------------------------- // Represents a class of the wx API/interface. // ---------------------------------------------------------------------------- class wxClass { public: wxClass() {} wxClass(const wxString& name, const wxString& headername) : m_strName(name), m_strHeader(headername) {} public: // setters void SetHeader(const wxString& header) { m_strHeader=header; } void SetName(const wxString& name) { m_strName=name; } void SetAvailability(int nAvail) { m_nAvailability=nAvail; } void SetParent(unsigned int k, const wxString& name) { m_parents[k]=name; } public: // getters bool IsOk() const { return !m_strName.IsEmpty() && !m_methods.IsEmpty(); } bool IsValidCtorForThisClass(const wxMethod& m) const; bool IsValidDtorForThisClass(const wxMethod& m) const; wxString GetName() const { return m_strName; } wxString GetHeader() const { return m_strHeader; } wxString GetNameWithoutTemplate() const; unsigned int GetMethodCount() const { return m_methods.GetCount(); } wxMethod& GetMethod(unsigned int n) const { return m_methods[n]; } wxMethod& GetLastMethod() const { return m_methods.Last(); } int GetAvailability() const { return m_nAvailability; } //const wxClass *GetParent(unsigned int i) const const wxString& GetParent(unsigned int i) const { return m_parents[i]; } unsigned int GetParentCount() const { return m_parents.GetCount(); } public: // misc void AddMethod(const wxMethod& func) { m_methods.Add(func); } void AddParent(const wxString& parent)//wxClass* parent) { m_parents.Add(parent); } // returns a single result (the first, which is also the only // one if CheckConsistency() return true) const wxMethod* FindMethod(const wxMethod& m) const; // like FindMethod() but this one searches also recursively in // the parents of this class. const wxMethod* RecursiveUpwardFindMethod(const wxMethod& m, const wxXmlInterface* allclasses) const; // returns an array of pointers to the overloaded methods with the // same given name wxMethodPtrArray FindMethodsNamed(const wxString& name) const; // like FindMethodsNamed() but this one searches also recursively in // the parents of this class. wxMethodPtrArray RecursiveUpwardFindMethodsNamed(const wxString& name, const wxXmlInterface* allclasses) const; // dumps all methods to the given output stream void Dump(wxTextOutputStream& stream) const; // slow check bool CheckConsistency() const; protected: wxString m_strName; wxString m_strHeader; wxMethodArray m_methods; // name of the base classes: we store the names and not the pointers // because this makes _much_ easier the parsing process! // (basically because when parsing class X which derives from Y, // we may have not parsed yet class Y!) wxArrayString m_parents; // see the wxMethod::m_nAvailability field for more info int m_nAvailability; }; WX_DECLARE_OBJARRAY(wxClass, wxClassArray); // ---------------------------------------------------------------------------- // wxXmlInterface // ---------------------------------------------------------------------------- class wxXmlInterface { public: wxXmlInterface() {} const wxClass* FindClass(const wxString& classname) const { for (unsigned int i=0; i typedef std::basic_string stlString; typedef std::map wxTypeIdHashMap; #endif // ---------------------------------------------------------------------------- // Represents the real interface of wxWidgets // Loads it from the XML produced by gccXML: http://www.gccxml.org // ---------------------------------------------------------------------------- class wxXmlGccInterface : public wxXmlInterface { public: wxXmlGccInterface() { // FIXME: we should retrieve this from the XML file! // here we suppose the XML was created for the currently-running port m_portId = wxPlatformInfo::Get().GetPortId(); } bool Parse(const wxString& filename); bool ParseMethod(const wxXmlNode *p, const wxTypeIdHashMap& types, wxMethod& m); wxPortId GetInterfacePort() const { return m_portId; } wxString GetInterfacePortName() const { return wxPlatformInfo::GetPortIdName(m_portId, false); } protected: // the port for which the gcc XML was generated wxPortId m_portId; }; // ---------------------------------------------------------------------------- // Represents the interface of the doxygen headers of wxWidgets // Loads it from the XML produced by Doxygen: http://www.doxygen.org // ---------------------------------------------------------------------------- class wxXmlDoxygenInterface : public wxXmlInterface { public: wxXmlDoxygenInterface() {} // !!SPEEDUP-TODO!! // Using wxXmlDocument::Load as is, the entire XML file is parsed // and an entire tree of wxXmlNodes is built in memory. // We need however only small portions of the Doxygen-generated XML: to speedup the // processing we could detach the expat callbacks when we detect the beginning of a // node we're not interested about, or just don't create a wxXmlNode for it! // This needs a modification of wxXml API. bool Parse(const wxString& filename); bool ParseCompoundDefinition(const wxString& filename); bool ParseMethod(const wxXmlNode*, wxMethod&, wxString& header); // this class can take advantage of the preprocessor output to give // a minor number of false positive warnings in the final comparison void AddPreprocessorValue(const wxString& name, const wxString& val) { m_preproc[name]=val; } protected: wxStringHashMap m_preproc; }; #endif // _XMLPARSER_H_